Spring: доступ к основным компонентам через ApplicationContext

#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:

Есть много разных способов сделать это.

  1. Установите primary=»true» в определении основного компонента. Если этот параметр установлен, то при наличии нескольких кандидатов для автоматической проводки первичному будет присвоен более высокий приоритет.
     <beans ...>
      <bean id="myPrimaryBeanId" class="mypackage.MyInterface" primary="true"/>
      <bean id="mySecondaryBeanId" class="mypackage.MyInterface" />
    </beans> 
     
  2. В качестве альтернативы, установите autowire-candidate=»false» для неосновных компонентов, если вы считаете, что этот компонент вообще не должен автоматически подключаться к какому-либо компоненту. Однако нужно быть осторожным при определении другого компонента с тем же интерфейсом, так как если вы забудете добавить это, снова будет несколько основных компонентов.
     <beans ...>
      <bean id="myPrimaryBeanId" class="mypackage.MyInterface"/>
      <bean id="mySecondaryBeanId" class="mypackage.MyInterface"
          autowire-candidate="false"/>
    </beans>    
     
  3. Будьте более конкретны в аннотациях автоматического подключения, используя именованные зависимости, которые можно архивировать с помощью @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. Я в замешательстве. Не могли бы вы переформулировать свою проблему