在我的应用程序中,我使用ContextLoaderListener从许多jar中加载上下文文件:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>
这意味着我可以在不进行导入的情况下从其他jar中引用bean。
在应用程序中有多个部署选项,在某些部署中可以排除jar。为了支持我,我希望一些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等于null(以某种方式将其标记为可选)
这可以在Spring完成吗?或者你推荐什么方法来处理动态参考?
答案 0 :(得分:25)
我最好的猜测是使用autowire - 使用必需的false。不知道如何在XML中表达这一点,但使用注释配置,这将是:
@Autowired(required=false)
答案 1 :(得分:13)
使用最新版本的Spring(使用Spring 4.1测试)和Java Configuration and Java 8,您可以在参数中使用Optional,并且只在可用时自动连接。
@Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
// do something with the optional autowired
}
答案 2 :(得分:10)
您建议使用哪种方法处理动态引用?
我认为@ cristian的@Autowired答案很好。如果该类型的bean可用,那将调用setter方法。但是,如果你有多个相同类型的bean,我相信Spring会抛出异常。如果由于这个或其他原因你不能使用@Autowired,我会看到几个解决方案:
您可以创建班级ApplicationContextAware
并自己在上下文中查找bean:
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.containsBean("optionalBeanReference1")) {
setOptionalBeanReference1(
(OptionalBeanReference1)applicationContext.bean(
"optionalBeanReference1");
}
...
}
您可以反转依赖关系。每个可选类都可以在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);
}
您可以继续使用直接依赖关系,然后导入一个定义了bean的文件,或者导入另一个文件,您可以使用工厂bean将bean定义为具有空值。请参阅此factory code。
答案 3 :(得分: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 :(得分:5)
鉴于XML配置中的bean引用是通过表达式语言(EL)定义的,您可以执行以下操作:
<property name="cache" value="#{getObject('optionalCache')}" />
使用BeanExpressionContext.getObject()
方法。有关详细信息,请参阅here。