如何在 Spring 中进行条件自动装配? [英] How to do conditional auto-wiring in Spring?

查看:37
本文介绍了如何在 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 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(或这个 example) 以了解如何以编程方式激活配置文件(即根据您的条件).

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 定义(例如,属性占位符 ${} 解析就是这样实现的).

BeanFactoryPostProcessors can read and alter bean definitions (e.g. property placeholder ${} resolution is implemented this way).

BeanPostProcessors 可以处理 bean 实例.可以检查新创建的 bean 并使用它(例如,@Scheduled 注释处理就是这样实现的).

BeanPostProcessors 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).

MergedBeanDefinitionPostProcessorbean post processor 的扩展,可以在实例化之前修改 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 has added a new method how to do conditional bean registration via @Conditional annotation. That is worth checking as well.

当然,通过 @ConditionalOn* 单独使用 Spring Boot 还有许多其他方法.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆