在Spring中如何进行条件自动接线? [英] How to do conditional auto-wiring in Spring?
问题描述
是否有人尝试根据条件将不同的bean自动连接到Spring管理的bean中?例如如果满足某些条件,则注入A类,否则注入B类?我在一个Google搜索结果中看到,可以使用SpEL(Spring表达式语言),但是找不到有效的示例.
Has anyone tried to auto-wire different beans into a Spring-managed bean based on a condition? For e.g. if some condition is met, inject class A, else B? I saw in one of the Google search results that it is possible with SpEL (Spring Expression Language), but could not locate a working example.
推荐答案
有多种方法可以实现此目的.通常,这取决于您要执行的条件.
There are multiple ways to achieve this. Mostly this depends on the conditioning you want to perform.
您可以实现简单的工厂bean来进行条件连接.这样的工厂bean可能包含复杂的条件逻辑:
You can implement simple factory bean to do the conditional wiring. Such factory bean can contain complex conditioning logic:
public MyBeanFactoryBean implements FactoryBean<MyBean> {
// Using app context instead of bean references so that the unused
// dependency can be left uninitialized if it is lazily initialized
@Autowired
private ApplicationContext applicationContext;
public MyBean getObject() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(applicationContext.getBean(DependencyX.class));
} else {
myBean.setDependency(applicationContext.getBean(DependencyY.class));
}
return myBean;
}
// Implementation of isSingleton => false and getObjectType
}
也许更好的方法是,如果您想在应用程序上下文中只使用一个这样的bean,则使用工厂bean 创建依赖bean .
Maybe a bit better approach is if you use factory bean to create the dependency bean in case you want to have only one such bean in your application context:
public MyDependencyFactoryBean implements FactoryBean<MyDependency> {
public MyDependency getObject() {
if (true /* some condition */) {
return new MyDependencyX();
} else {
return new MyDependencyY();
}
}
// Implementation of isSingleton => false and getObjectType
}
SpEL
有了SpEL,就有很多可能性.最常见的是系统属性根据条件:
<bean class="com.example.MyBean">
<property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" />
</bean>
属性占位符
您可以让属性占位符解析您的bean引用.依赖项名称可以是应用程序配置的一部分.
Property placeholder
You can have property placeholder resolve your bean reference. The dependency name can be part of the application configuration.
<bean class="com.example.MyBean">
<property name="dependency" ref="${dependencyName}" />
</bean>
春季概况
通常,您要评估的条件意味着应注册或不应该注册整套bean. Spring配置文件可用于此目的:
Spring profiles
Usually the condition you want to evaluate means that a whole set of beans should or should not be registered. Spring profiles can be used for this:
<!-- Default dependency which is referred by myBean -->
<bean id="dependency" class="com.example.DependencyX" />
<beans profile="myProfile">
<!-- Override `dependency` definition if myProfile is active -->
<bean id="dependency" class="com.example.DependencyY" />
</beans>
其他方法可以将Bean定义标记为lazy-init="true"
,但是该定义仍将在应用程序上下文中注册(并在使用不合格的自动装配时增加您的工作难度).您还可以通过@Profile
批注将概要文件与基于@Component
的bean一起使用.
Other methods can mark the bean definition as lazy-init="true"
, but the definition will be still registered inside application context (and making your life harder when using unqualified autowiring). You can also use profiles with @Component
based beans via @Profile
annotation.
检查 ApplicationContextInitialier
(或此示例),了解如何以编程方式(即根据您的条件)激活配置文件.
Check ApplicationContextInitialier
(or this example) to see how you can activate profiles programatically (i.e. based on your condition).
这就是为什么基于Java的配置如此受欢迎的原因:
This is why Java based config is being so popular as you can do:
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(dependencyX());
} else {
myBean.setDependency(dependencyY());
}
return myBean;
}
当然,您也可以在基于Java的配置中使用或多或少地使用所有配置方法(通过@Profile
,@Value
或@Qualifier
+ @Autowired
).
Of course you can use more or less all configuration methods in the java based config as well (via @Profile
, @Value
or @Qualifier
+ @Autowired
).
Spring提供了许多挂钩点和SPI,您可以在其中参与应用程序上下文生命周期.本节需要更多有关Spring内部工作的知识.
Spring offers numerous hook points and SPIs, where you can participate in the application context life-cycle. This section requires a bit more knowledge of Spring's inner workings.
BeanFactoryPostProcessor
可以读取和更改Bean定义(例如,以这种方式实现属性占位符${}
解析).
BeanFactoryPostProcessor
s can read and alter bean definitions (e.g. property placeholder ${}
resolution is implemented this way).
BeanPostProcessor
可以处理Bean实例.可以检查新创建的bean并使用它(例如,@Scheduled
注释处理是通过这种方式实现的).
BeanPostProcessor
s can process bean instances. It is possible to check freshly created bean and play with it (e.g. @Scheduled
annotation processing is implemented this way).
MergedBeanDefinitionPostProcessor
是 bean后处理器的扩展,可以在实例化bean之前更改它的定义(以这种方式实现@Autowired
注释处理).
MergedBeanDefinitionPostProcessor
is extension of bean post processor and can alter the bean definition just before it is being instantiated (@Autowired
annotation processing is implemented this way).
2015年10月更新
-
Spring 4添加了一种新方法
@Conditional
批注.这也值得检查.
Spring 4 has added a new method how to do conditional bean registration via
@Conditional
annotation. That is worth checking as well.
当然,通过Spring Boot的@ConditionalOn*
还有很多其他方式.
Of course there are numerous other ways with Spring Boot alone via its @ConditionalOn*
.
还请注意,@Import
和@ComponentScan
(及其XML对应版本)都经过属性解析(即,您可以使用${}
).
Also note that both @Import
and @ComponentScan
(and their XML counterparts) undergo property resolution (i.e. you can use ${}
).
这篇关于在Spring中如何进行条件自动接线?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!