Spring создает два beans из одного класса с помощью аннотаций
Я могу создать из двух beans из одного класса java, используя конфигурацию xml, используя следующий код:
<context:component-scan base-package="some.package"/>
<bean id="dependentBean" class="some.package.DependentBean">
<property name="firstBean" ref="firstBean"/>
</bean>
<bean id="firstBean" class="some.package.Handler">
<constructor-arg index="0" ref="service"></constructor-arg>
<property name="defaultUrl" value="url/first"></property>
</bean>
<bean id="secondBean" class="some.package.Handler">
<constructor-arg index="0" ref="service"></constructor-arg>
<property name="defaultUrl" value="url/second"></property>
</bean>
Моя цель - перенести firstBean и secondBean в конфигурацию на основе java, например:
package some.package;
@Configuration
public class Configuration {
@Bean(name="firstBean")
public Handler firstHandler(Service service){
Handler handler= new Handler(service);
handler.setDefaultTargetUrl("url/first");
return handler;
}
@Bean(name="secondBean")
public Handler secondHandler(Service service){
Handler handler = new Handler(service);
handler.setDefaultTargetUrl("url/second");
return handler;
}
}
Но когда контекст начинает загрузку spring выдает следующее исключение:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'firstBean' is defined
Тем не менее он работает в этом случае:
package some.package;
@Component
public class Filter{
private Handler handler;
@Autowired
public Filter(@Qualifier("secondBean") Handler handler) {
this.handler = handler;
}
}
Выполнение обработчика:
public class Handler {
private Service service;
@Autowired
public Handler(Service service) {
this.service = service;
}
}
Ответы
Ответ 1
@Autowired
всегда по типу. Но у вас есть два обработчика в вашей конфигурации. Поэтому, когда вы пытаетесь autwire класса обработчика, вы должны указать квалификатор. Этим spring может разрешить, какой экземпляр будет введен. Else, spring выдает сообщение об ошибке NoSuchBeanDefinitionFoundError
. Ожидаемый найден два.
Надеюсь, что это поможет.
Ответ 2
Из Spring Docs, раздел 5.9.3:
Если вы намереваетесь выражать введенную аннотацией инъекцию по имени, не используйте в основном @Autowired, даже если технически можно ссылаться на имя bean через значения @Qualifier. Вместо этого используйте аннотацию JSR-250 @Resource, которая семантически определена для идентификации конкретного целевого компонента по его уникальному имени, причем объявленный тип не имеет отношения к процессу сопоставления.
Вот пример этого в разделе 5.9.5, но для вашего кода класс Фильтр должен выглядеть так:
package some.package;
@Component
public class Filter {
private Handler handler;
@Resource(name="secondBean")
public Filter(Handler handler) {
this.handler = handler;
}
}