Аннотация @Qualifier не работает должным образом и сообщает: классу требуется один компонент, но найдено 2:

Я хочу реализовать шаблон CircuitBreaker в приложении весенней загрузки. У меня есть два API, и каждый API имеет свою собственную конфигурацию. Я определил эти два метода конфигурации в классе приложения. Кроме того, в классе приложения я определил Spring Bean типа CustomCircuitBreakerFactory. Этот тип является пользовательским классом и будет создан для управления и настройки автоматических выключателей для API. Этот Spring bean-компонент принимает в своем конструкторе три параметра:

import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;

import org.springframework.context.annotation.Bean;

import java.time.Duration;
import java.util.List;


@SpringBootApplication(scanBasePackages = {"com.company.*"})
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }

    @Bean
    @Qualifier("api1CircuitBreakerConfig")
    public CircuitBreakerConfig api1CircuitBreakerConfig() {

        return CircuitBreakerConfig.custom()
            .failureRateThreshold(50)
            .waitDurationInOpenState(Duration.ofSeconds(10))
            .permittedNumberOfCallsInHalfOpenState(10)
            .slidingWindowSize(100)
            .minimumNumberOfCalls(20)
            .recordExceptions(RuntimeException.class, CallNotPermittedException.class)
            .build();
    }

    @Bean
    @Qualifier("api2CircuitBreakerConfig")
    public CircuitBreakerConfig api2CircuitBreakerConfig() {
        return CircuitBreakerConfig.custom()
            .failureRateThreshold(40)
            .waitDurationInOpenState(Duration.ofSeconds(10))
            .permittedNumberOfCallsInHalfOpenState(10)
            .slidingWindowSize(150)
            .minimumNumberOfCalls(30)
            .recordExceptions(RuntimeException.class, CallNotPermittedException.class)
            .build();

    }

    @Bean
    public CustomCircuitBreakerFactory customCircuitBreakerFactory(
        ReactiveResilience4JCircuitBreakerFactory circuitBreakerFactory,
        CircuitBreakerConfig api1CircuitBreakerConfig,
        CircuitBreakerConfig api2CircuitBreakerConfig) {
        return new CustomCircuitBreakerFactory(circuitBreakerFactory, api1CircuitBreakerConfig, api2CircuitBreakerConfig);
    }
}


Это реализация CustomCircuitBreakerFactory. Это класс компонентов для настройки автоматических выключателей и управления ими. Его конструктор принимает три параметра и имеет два метода для создания и настройки экземпляров автоматических выключателей для каждого из базовых API.

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class CustomCircuitBreakerFactory {

    private final ReactiveResilience4JCircuitBreakerFactory circuitBreakerFactory;
    private final CircuitBreakerConfig api1CircuitBreakerConfig;
    private final CircuitBreakerConfig api2CircuitBreakerConfig;


    public CustomCircuitBreakerFactory(
        ReactiveResilience4JCircuitBreakerFactory circuitBreakerFactory,
        @Qualifier("api1CircuitBreakerConfig") CircuitBreakerConfig api1CircuitBreakerConfig,
        @Qualifier("api2CircuitBreakerConfig") CircuitBreakerConfig api2CircuitBreakerConfig) {
        this.circuitBreakerFactory = circuitBreakerFactory;
        this.api1CircuitBreakerConfig= api1CircuitBreakerConfig;
        this.api2CircuitBreakerConfig= api2CircuitBreakerConfig;
    }


    public CircuitBreaker createApi1CircuitBreaker() {
        return (CircuitBreaker) circuitBreakerFactory.create("api1");
    }

    public CircuitBreaker createApi2CircuitBreaker() {
        return (CircuitBreaker) circuitBreakerFactory.create("api2");
    }
}

Когда я запустил приложение, я получил эту ошибку: Параметр 1 метода customCircuitBreakerFactory в ApiApplication требовал одного bean-компонента, но были найдены 2: - api1CircuitBreakerConfig: определяется методом api1CircuitBreakerConfig в ApiFacadeApplication. - api2CircuitBreakerConfig: определяется методом api2CircuitBreakerConfig в ApiFacadeApplication. Я использовал @Qualifier, но он не работает.

Я использовал @Qualifier, но он не работает.

Не хватает @Autowired в конструкторе?

Vasily Liaskovsky 11.04.2024 14:00

кажется, вы передаете параметры конструктору, управляемому пружиной, эти параметры управляются неправильно

Stultuske 11.04.2024 14:01

Ой, подождите, на самом деле он жалуется не на конструктор, а на ApiApplication.customCircuitBreakerFactory. Вы должны использовать @Qualifier в параметрах этого метода.

Vasily Liaskovsky 11.04.2024 14:03

Да! теперь это работает! Я удалил @Qualifier из определения конструктора CustomCircuitBreakerFactory и добавил его в ApiApplication.customCircuitBreakerFactory.

Misa 11.04.2024 14:06
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем коде есть несколько проблем

  1. @Qualifier оказывает эффект, когда компонент вводится, но не предоставляется. Установка пользовательского квалификатора для компонента возможна с помощью аннотаций, создающих компонент: @Bean, @Service, @Component или подобных.
  2. И @Component, и @Bean добавляют компонент в контекст Spring. Вам следует использовать любой из них, но не оба.
  3. @Qualifier следует использовать везде, где происходит процесс автоподключения.

Итак, шаги, которые помогут вашему коду работать:

  1. Удалите @Qualifier на api1CircuitBreakerConfig() и api2CircuitBreakerConfig() и вместо этого добавьте имена в аннотации @Bean. Обратите внимание, что по умолчанию Spring использует квалификатор, равный имени метода/класса, поэтому в вашем случае он избыточен.
  2. Удалить @Component из CustomCircuitBreakerFactory
  3. Добавьте аннотации @Qualifer к параметрам ApiApplication.customCircuitBreakerFactory

Другие вопросы по теме