#java #spring #dependency-injection #javabeans #autowired
#java #spring #внедрение зависимостей #javabeans #автоматическое подключение
Вопрос:
Если у меня есть 2 компонента в моем ApplicationContext, реализующие один и тот же интерфейс, я могу пометить один из них как основной в определении компонента. Этот компонент предпочтительнее для внедрения зависимостей.
Есть ли способ получить прямой доступ с помощью ApplicationContext к основному без DI?
Комментарии:
1. Это известная ошибка в Spring 3.0, которая была исправлена в Spring 3.2: jira.spring.io/browse/SPR-7854
Ответ №1:
Есть много разных способов сделать это.
- Установите primary=»true» в определении основного компонента. Если этот параметр установлен, то при наличии нескольких кандидатов для автоматической проводки первичному будет присвоен более высокий приоритет.
<beans ...> <bean id="myPrimaryBeanId" class="mypackage.MyInterface" primary="true"/> <bean id="mySecondaryBeanId" class="mypackage.MyInterface" /> </beans>
- В качестве альтернативы, установите autowire-candidate=»false» для неосновных компонентов, если вы считаете, что этот компонент вообще не должен автоматически подключаться к какому-либо компоненту. Однако нужно быть осторожным при определении другого компонента с тем же интерфейсом, так как если вы забудете добавить это, снова будет несколько основных компонентов.
<beans ...> <bean id="myPrimaryBeanId" class="mypackage.MyInterface"/> <bean id="mySecondaryBeanId" class="mypackage.MyInterface" autowire-candidate="false"/> </beans>
- Будьте более конкретны в аннотациях автоматического подключения, используя именованные зависимости, которые можно архивировать с помощью @javax.annotation .Аннотация ресурса, как показано ниже. Это уменьшит сложность кода при определении того, какой компонент мог быть введен, поскольку можно просто найти компонент по идентификатору.
@Resource(name="myPrimaryBeanId") protected MyInterface myInstance;
Метод инъекции без зависимости (DI)
Если вы предпочитаете не использовать DI, вы можете использовать следующее, чтобы извлечь компонент по имени из ApplicationContext
MyInterface myInstance = (MyInterface)
applicationContext.getBean("myPrimaryBeanId");
Если вы хотите использовать не метод DI, а компонент spring, и если у вас нет дескриптора контекста spring для этого, вы можете изменить свой класс для реализации org.springframework.context.Интерфейс ApplicationContextAware, который потребует от вас реализации метода setApplicationContext(ApplicationContext), в который spring введет дескриптор в текущий контекст приложения, как показано ниже.
public class MyBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
private String MY_PRIMARY_BEAN_ID = "myPrimaryBeanId";
public void myMethod() {
MyInterface myInstance = getMyPrimaryBean();
// do my logic here
}
private MyInterface getMyPrimaryBean() {
return (MyInterface) applicationContext.getBean(MY_PRIMARY_BEAN_ID);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
Примечание: этот ответ основан на Spring 2.5.x
Ответ №2:
Сначала вам понадобится ваш BeanFactory / ApplicationContext. Вы можете получить его, например, путем реализации BeanFactoryAware. Предполагая, что это ConfigurableListableBeanFactory, вы можете проверить, что является основным для данного типа следующим образом:
ConfigurableListableBeanFactory clbf =
(ConfigurableListableBeanFactory)beanFactory;
String[] beanNames = clbf.getBeanNamesForType(myType);
for (String beanName : beanNames) {
BeanDefinition bd = clbf.getBeanDefinition(beanName);
if (bd.isPrimary()) {
...
}
}
Ответ №3:
Просто объявите его как компонент и установите зависимость вручную, выбрав из ApplicationContext и установив его. Но вы нарушите инверсию управления
Комментарии:
1. К сожалению, в этом случае я не могу решить, какой компонент является основным, потому что я могу получить только имя и сам компонент из контекста. У меня нет доступа к метаданным определения компонента.
2. Наличие двух компонентов с одинаковым идентификатором в контексте на самом деле не спасает. Иногда это работает, но Spring не рекомендует.
3. Я в замешательстве. Не могли бы вы переформулировать свою проблему