如何在 Spring 中进行条件自动装配?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19225115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do conditional auto-wiring in Spring?
提问by Paddy
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.
有没有人尝试根据条件将不同的 bean 自动连接到 Spring 管理的 bean 中?例如,如果满足某些条件,则注入 A 类,否则注入 B?我在 Google 搜索结果之一中看到 SpEL(Spring 表达式语言)是可能的,但找不到工作示例。
回答by Pavel Horal
There are multiple ways to achieve this. Mostly this depends on the conditioning you want to perform.
有多种方法可以实现这一点。这主要取决于您想要执行的调节。
Factory bean
工厂豆
You can implement simple factory bean to do the conditional wiring. Such factory bean can contain complex conditioning logic:
您可以实现简单的工厂 bean 来进行条件连接。这样的工厂 bean 可以包含复杂的条件逻辑:
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
}
Maybe a bit better approach is if you use factory beanto create the dependency beanin case you want to have only one such bean in your application context:
也许更好的方法是使用工厂 bean创建依赖 bean,以防您希望在应用程序上下文中只有一个这样的 bean:
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
斯佩尔
With SpEL there are many possibilities. Most common are system propertybased conditions:
使用 SpEL 有很多可能性。最常见的是基于系统属性的条件:
<bean class="com.example.MyBean">
<property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" />
</bean>
Property placeholder
属性占位符
You can have property placeholder resolve your bean reference. The dependency name can be part of the application configuration.
您可以让属性占位符解析您的 bean 引用。依赖项名称可以是应用程序配置的一部分。
<bean class="com.example.MyBean">
<property name="dependency" ref="${dependencyName}" />
</bean>
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:
通常,您要评估的条件意味着应该或不应该注册一整套 bean。弹簧配置文件可用于此:
<!-- 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>
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 @Componentbased beans via @Profileannotation.
其他方法可以将 bean 定义标记为lazy-init="true",但该定义仍将在应用程序上下文中注册(并且在使用不合格的自动装配时会使您的生活更加困难)。您还可以@Component通过@Profile注释使用基于 bean 的配置文件。
Check ApplicationContextInitialier(or this example) to see how you can activate profiles programatically (i.e. based on your condition).
检查ApplicationContextInitialier(或此示例)以了解如何以编程方式(即根据您的条件)激活配置文件。
Java config
Java配置
This is why Java based config is being so popular as you can do:
这就是基于 Java 的配置如此受欢迎的原因:
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(dependencyX());
} else {
myBean.setDependency(dependencyY());
}
return myBean;
}
Of course you can use more or less all configuration methods in the java based config as well (via @Profile, @Valueor @Qualifier+ @Autowired).
当然,您也可以或多或少地使用基于 java 的配置中的所有配置方法(通过@Profile,@Value或@Qualifier+ @Autowired)。
Post processor
后处理器
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.
Spring 提供了许多挂钩点和 SPI,您可以在其中参与应用程序上下文生命周期。本节需要更多有关 Spring 内部工作原理的知识。
BeanFactoryPostProcessors can read and alter bean definitions (e.g. property placeholder ${}resolution is implemented this way).
BeanFactoryPostProcessors 可以读取和更改 bean 定义(例如,以${}这种方式实现属性占位符解析)。
BeanPostProcessors can process bean instances. It is possible to check freshly created bean and play with it (e.g. @Scheduledannotation processing is implemented this way).
BeanPostProcessors 可以处理 bean 实例。可以检查新创建的 bean 并使用它(例如,以@Scheduled这种方式实现注释处理)。
MergedBeanDefinitionPostProcessoris extension of bean post processorand can alter the bean definition just before it is being instantiated (@Autowiredannotation processing is implemented this way).
MergedBeanDefinitionPostProcessor是bean 后处理器的扩展,可以在实例化之前更改 bean 定义(@Autowired注释处理以这种方式实现)。
UPDATE Oct 2015
2015 年 10 月更新
Spring 4 has added a new method how to do conditional bean registrationvia
@Conditionalannotation. That is worth checking as well.Of course there are numerous other ways with Spring Boot alone via its
@ConditionalOn*.Also note that both
@Importand@ComponentScan(and their XML counterparts) undergo property resolution (i.e. you can use${}).
Spring 4 添加了如何通过注解进行条件 bean 注册的新方法
@Conditional。这也值得检查。当然,仅通过 Spring Boot 就可以通过其
@ConditionalOn*.另请注意,
@Import和@ComponentScan(以及它们的 XML 对应项)都经过属性解析(即您可以使用${})。
回答by fascynacja
I had a case where I needed to inject different beans depending on property: "my.property". In my case this solution was successful:
我有一个案例,我需要根据属性注入不同的 bean:“my.property”。在我的情况下,这个解决方案是成功的:
<property name="name" ref="#{ ${my.property:false}==true ? 'bean1' : 'bean2' }"/>
I needed to add the apostrophes around bean names in order to make it work.
我需要在 bean 名称周围添加撇号以使其工作。

