2010-10-18 2 views
16

В моем приложении я использую ContextLoaderListener загрузить файлы контекста из многих баночек с помощью:Дополнительные ссылки Spring боб

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath*:META-INF/contextBeans.xml</param-value> 
</context-param> 

Это означает, что я могу ссылаться на бобы из других банок, не делая импорт.

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

<bean id="mainAppBean" class="com.someapp.MyApplication"> 
    <constructor-arg index="0" ref="localBean"/> 
    <constructor-arg index="1" ref="optionalBeanReference1"/> 
    <constructor-arg index="2" ref="optionalBeanReference2"/> 
</bean> 

В приведенном выше примере, я хотел бы иметь optionalBeanReference1 равный нуль, если ссылка не была найдена (маркировать необязательным в некотором роде)

Может ли это быть сделано весной? или какой метод вы рекомендуете для обработки динамических ссылок?

ответ

9

какой метод вы рекомендуете для обработки динамических ссылок?

Я думаю, что @ cristian's @Autowired ответ хороший. Это вызовет методы setter, если бобы этого типа доступны. Однако, если у вас несколько бобов того же типа, я считаю, что Spring выбрасывает исключение. Если вы не можете использовать @Autowired для той или иной причине, я вижу несколько решений:

  1. Вы можете сделать свой класс ApplicationContextAware и поиска бобы в контексте сами:

    public void setApplicationContext(ApplicationContext applicationContext) { 
        if (applicationContext.containsBean("optionalBeanReference1")) { 
         setOptionalBeanReference1(
          (OptionalBeanReference1)applicationContext.bean(
           "optionalBeanReference1"); 
        } 
        ... 
    } 
    
  2. Вы можете инвертировать зависимость. Каждый из необязательных классов мог установить самостоятельно на mainAppBean. Я использую это в определенных ситуациях, когда прямая зависимость вызывает циклы или другие проблемы.

    <bean id="optionalBeanReference1" class="com.someapp.SomeClass"> 
        <constructor-arg index="0" ref="mainAppBean"/> 
    </bean> 
    

    Тогда в SomeClass:

    public SomeClass(com.someapp.MyApplication mainAppBean) { 
        mainAppBean.setOptionalBeanReference1(this); 
    } 
    
  3. Вы могли бы остаться с прямой зависимостью, а затем либо импортировать файл с установленными бобами или импортировать другой файл, в котором вы определяете бобы как имеющие нулевые значения используя фабричный компонент. См. Это factory code.

Удачи.

+0

Я использовал что-то похожее на первый вариант, где после загрузки компонента я проверяю, существуют ли другие компоненты. Это выглядит наилучшим образом без аннотаций. – mbdev

23

Мое лучшее предположение - использовать autowire -инг с требуемым ложным. Не знаю, как вы можете выразить это в XML, но с использованием конфигурации аннотаций это будет выглядеть так:

@Autowired(required=false) 
+1

О, да, и инъекция сеттера, вероятно, лучше для таких ситуаций. –

+0

Звучит неплохо, но я пока не могу использовать аннотации Spring в проекте. – mbdev

5

Для этого нет встроенного механизма.Тем не менее, вы могли бы написать довольно тривиальное FactoryBean реализации, чтобы сделать это для вас, что-то вроде этого:

public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware { 

    private String beanName; 

    @Override 
    public void setBeanName(String beanName) { 
     this.beanName = BeanFactoryUtils.originalBeanName(beanName); 

    } 

    @Override 
    protected Object createInstance() throws Exception { 
     if (getBeanFactory().containsBean(beanName)) { 
      return getBeanFactory().getBean(beanName); 
     } else { 
      return null; 
     } 
    } 

    @Override 
    public Class<?> getObjectType() { 
     return null; 
    } 
} 

Вы можете использовать его как это:

<bean id="mainAppBean" class="com.someapp.MyApplication"> 
    <constructor-arg index="0" ref="localBean"/>  
    <constructor-arg index="1"> 
     <bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/> 
    </constructor-arg> 
    <constructor-arg index="2"> 
     <bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/> 
    </constructor-arg> 
</bean> 
4

Учитывая, что ссылки боб в вашем XML конфигурации определяются с помощью выражения языка (EL), вы можете сделать следующее:

<property name="cache" value="#{getObject('optionalCache')}" /> 

, который использует метод BeanExpressionContext.getObject(). См. here для получения более подробной информации.

7

С последними версиями Spring (протестированных с весной 4.1) и конфигурацией Java и Java 8 вы можете использовать опцию в параметрах и только в том случае, если они доступны.

@Autowired 
public MyApplication(Optional<YourOptionalObject> maybeObject) { 
    // do something with the optional autowired 
} 
+1

См. Билет на улучшение весны здесь: https://jira.spring.io/browse/SPR-11833 и фактический пример здесь: https://stackoverflow.com/questions/19485878/can -inject-be-made-optional-in-jsr-330-like-autowirerequired-false –

+0

это лучшее решение! Оно работает! Благодаря! – Torsten

Смежные вопросы