如何在春季做条件自动布线?

有没有人试图根据条件将不同的bean自动连接到Springpipe理的bean? 例如,如果满足一些条件,注入类A,否则B? 我在其中一个Googlesearch结果中看到使用SpEL(Spring Expression Language)是可能的,但是找不到一个可行的例子。

有多种方法来实现这一点。 大多数情况下,这取决于你想要执行的条件。

工厂bean

你可以实现简单的工厂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 } 

如果你想在你的应用程序上下文中只有一个这样的bean的话,使用factory bean来创build依赖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有许多可能性。 最常见的是基于系统属性的条件:

 <bean class="com.example.MyBean"> <property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" /> </bean> 

属性占位符

你可以让属性占位符parsing你的bean引用。 依赖项名称可以是应用程序configuration的一部分。

 <bean class="com.example.MyBean"> <property name="dependency" ref="${dependencyName}" /> </bean> 

spring概况

通常情况下,你想评估的条件意味着一整套的豆应该或不应该注册。 springconfiguration文件可以用于这个:

 <!-- 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" ,但定义将仍然在应用程序上下文中注册(并且在使用不合格的自动assembly时使生活更加困难)。 您还可以通过@Profile注释使用基于@Component的bean的configuration文件。

检查ApplicationContextInitialier (或这个例子 ),看看如何以编程方式激活configuration文件(即根据您的条件 )。

Javaconfiguration

这就是为什么基于Java的configuration如此受欢迎,因为你可以这样做:

 @Bean public MyBean myBean() { MyBean myBean = new MyBean(); if (true /* some condition */) { myBean.setDependency(dependencyX()); } else { myBean.setDependency(dependencyY()); } return myBean; } 

当然你也可以在基于java的configuration中使用或多或less的所有configuration方法(通过@Value@Value或者@Qualifier + @Autowired )。

后处理器

Spring提供了许多钩点和SPI,您可以在其中参与应用程序上下文的生命周期。 这部分需要更多的关于Spring内部工作的知识。

BeanFactoryPostProcessor可以读取和修改bean的定义(例如,属性占位符${}是以这种方式实现的)。

BeanPostProcessor可以处理bean实例。 可以检查刚刚创build的bean并使用它(例如@Scheduled注释处理是以这种方式实现的)。

MergedBeanDefinitionPostProcessorbean后期处理器的扩展,可以在实例化之前改变bean的定义( @Autowired注解处理是以这种方式实现的)。


更新2015年10月

  • Spring 4增加了一个新的方法,通过@Conditional注释来实现条件bean的注册 。 这也值得检查。

  • 当然,通过它的@ConditionalOn*单独使用Spring Boot还有很多其他的方法。

  • 还要注意, @Import@ComponentScan (及其XML对应)都经过属性parsing(即可以使用${} )。