有没有人尝试根据条件将不同的bean自动连接到Spring管理的bean中?例如,如果满足某些条件,则注入A类,否则注入B类?我在一个Google搜索结果中看到,使用SpEL(Spring表达式语言)是可能的,但找不到有效的示例。
有多种方法可以实现此目的。通常,这取决于你要执行的条件。
Factory 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,则使用工厂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
使用SpEL,有很多可能性。最常见的是基于系统属性的条件:
<bean class="com.example.MyBean"> <property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" /> </bean>
Property placeholder
你可以让属性占位符解析你的bean引用。依赖项名称可以是应用程序配置的一部分。
<bean class="com.example.MyBean"> <property name="dependency" ref="${dependencyName}" /> </bean>
Spring profiles
通常,要评估的条件意味着应注册或不应该注册整套bean。Spring配置文件可用于此目的:
<!-- 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”,但是该定义仍将在应用程序上下文中注册(并且在使用不合格的自动装配时会使你的生活更加艰难)。你也可以@Component通过@Profile注释将概要文件与基于bean的文件一起使用。
@Component
@Profile
检查ApplicationContextInitialier(或此示例)以查看如何以编程方式(即根据你的状况)激活配置文件。
Java config
这就是为什么基于Java的配置如此受欢迎的原因:
@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)。
@Qualifier+ @Autowired
Post processor
Spring提供了许多挂钩点和SPI,你可以在其中参与应用程序上下文生命周期。本节需要更多有关Spring内部工作的知识。
Spring
BeanFactoryPostProcessor可以读取和更改bean定义(例如,以${}这种方式实现属性占位符解析)。
BeanFactoryPostProcessor
${}
BeanPostProcessor可以处理bean实例。可以检查新创建的bean并使用它(例如,以@Scheduled这种方式实现注释处理)。
BeanPostProcessor
@Scheduled
MergedBeanDefinitionPostProcessor是bean后处理器的扩展,可以在实例化bean之前更改bean的定义(以@Autowired这种方式实现注释处理)。
MergedBeanDefinitionPostProcessor
@Autowired
Spring 4添加了一种新方法,该方法如何通过注释进行条件Bean注册@Conditional。这也值得检查。
当然,通过Spring Boot单独使用Spring Boot还有许多其他方法@ConditionalOn*。
另请注意,@Import和和@ComponentScan(及其XML对应项)都经过属性解析(即可以使用${})。
@Import
@ComponentScan