Как Spring решает, какой бин добавить, если в @Qualifier определены два кандидата? - PullRequest
0 голосов
/ 14 февраля 2020

Предположим, у меня есть два bean-компонента, определенных следующим образом:

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

Когда я автоматически подключаю restTemplate без предоставления @Qualifier, какой компонент будет введен? Как это решено?

@Service
public class someClass {

    @Autowired
    private RestTemplate restTemplate;

} 

Примечание: при тестировании вводится один из бобов. Это не привело ни к какому исключению.

Примечание2: я знаю, что могу использовать @Qualifier для внедрения нужного компонента или использовать @Primary, чтобы избежать двусмысленности. Но Я просто хочу понять, почему он действителен для Spring.

Примечание 3: Когда я изменил имя метода в классе ConfigurationB на restTemplateB, бин, определенный в ConfigurationA, вводится. Опять же это не привело ни к какому исключению.

Я пробовал это в Spring Boot версии 1.4.4

Ответы [ 3 ]

1 голос
/ 14 февраля 2020

Я думаю, что вы найдете, если вы запустите ваше приложение, оно будет регистрировать ошибку вроде requried a single bean but 2 were found.

Что вы можете сделать, однако, это удалить неопределенность, используя @Qualifier там, где вам это нужно внедрил и назвал ваши определения бина, т.е. для вашего примера.

@Configuration
public class Configuration {

    @Bean(name="restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }

    @Bean(name="restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

Затем, когда вы перейдете к внедрению и использованию шаблонов

@Service
public class someClass {

    @Autowired
    @Qualifer("restTemplateA")
    private RestTemplate restTemplate;

} 

Однако вы также можете пометить один из шаблонов как Primary с помощью @Primary, и этот компонент будет затем использовать в каждом месте, которое вы не квалифицируете как свой автопровод.

    @Bean(name="restTemplateA")
    @Primary
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
1 голос
/ 15 февраля 2020

Case1: Те же имена методов (бинов) в классах конфигурации.

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

Результат: вставлен restTemplate в ConfigationB. restTemplate в ConfiguratioA переопределяется с помощью restTemplate в ConfigurationB, что можно найти в журналах:

osbfsDefaultListableBeanFactory: Переопределение определения компонента для компонента 'restTemplate' с компонентом restTemplate другое определение: замена ...

Важное примечание : переопределение бина по умолчанию отключено в весенней загрузке версии 2.1 (вы можете проверить эту ссылку )

Case2: Изменение имени метода в ConfigurationB на restTemplateB.

@Configuration
public class ConfigurationA {

    @Bean
    @Qualifier("restTemplateA")
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

@Configuration
public class ConfigurationB {

    @Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplateB() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }
}

Результат: Оба компонента в ConfigurationA созданы в ConfigurationB. Бин в Конфигурации А вводится. Потому что имя bean-компонента будет использоваться, если автоматическое подключение по типу не находит ни одного соответствующего bean-компонента. Проверьте это для получения дополнительной информации

1 голос
/ 14 февраля 2020

На самом деле у вас не может быть обоих классов конфигурации, потому что вы получите конфликт имен бинов. Чтобы это исправить, переименуйте имя метода:

@Bean
    @Qualifier("restTemplateB")
    public RestTemplate restTemplateB() {
        RestTemplate restTemplate = new RestTemplate();

        //setting some restTemplate properties

        return restTemplate;
    }

Таким образом, два RestTemplate будут созданы с именами restTemplate и restTemplateB соответственно, а первое будет введено в классе обслуживания .

...