@Conditional & @Profile SpringBoot中自动化配置条件注解使用事件。

定义

Spring4 中提供了更加通用的条件注解,让我们可以在满足不同条件时创建不同的 Bean,这种配置方式在 Spring Boot 中得到了广泛的使用,大量的自动化配置都是通过条件注解来实现的。条件注解作用是让Spring根据不同条件生产不同的Bean。

注意:这里不同的Bean应该是指同一类不同对象个人理解)。

实践

Condition注解

首先建立一个普通Maven项目,引入Spring-context相关依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
</dependencies>

首先定义一个接口,同时定义俩个实现类:

// World接口
public interface World {
    String showName();
}

//China实现类
public class China implements World{
    public String showName(){
        return "China";
    }
}

//American实现类
public class American implements World{
    public String showName(){
        return "American";
    }
}

这里也可以直接定义一个类写上完整的构造方法,后面在生产Bean中通过不同构造参数产生不同实例进行模拟。

分别为China和American配置条件类:

public class ChinaCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata){
        return context.getEnvironment().getProperty("country").equals("中国");
    }
}

public class AmericanCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata){
        return context.getEnvironment().getProperty("country").equals("美国");
    }
}

注意:此处Condition接口是来自:

import org.springframework.context.annotation.Condition;

接下来还需要个配置类:

@Configuration
public class ConditionConfig {
    @Bean("country")
    @Conditional(ChinaCondition.class)
    World china(){
        return new China();
    }

    @Bean("country")
    @Conditional(AmericanCondition.class)
    World american(){
        return new American();
    }
}
  • @Bean("country")等同于@Bean(name = "country"),表示对产生的Bean进行命名(个人理解)

  • @Condition就是我们此次所讲的关键,这个注解中的必须继承Condition接口,如果该类的matches()返回true则生产Bean,否则忽视后面的函数。

最后,我们需要一个主函数:

public class ConditionMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext actx = new AnnotationConfigApplicationContext();
        actx.getEnvironment().getSystemProperties().put("country", "中国");
        actx.register(ConditionConfig.class);
        actx.refresh();

        World world = (World) actx.getBean("country");
        System.out.println(world.showName());
    }
}

首先我们创建一个AnnotationConfigApplicationContext的实例化对象 actx,对actx中注入相关参数,put()接受的是一个键值对,再注册配置类ConditionConfig,最后刷新容器。

容器刷新时Spring才会开始调用ConditionConfig对之前信息进行处理,然后根据插入的键值对产生相应的Bean。最后用一个将名为country的Bean赋值给World实例。

对于AnnotationConfigApplicationContext可以理解为:

AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。从而代替Xml文件。

@Profile

使用注解@Profile可以避免自己在matches()中写业务逻辑的过程,更简单的实现以上过程。

对于World接口,China、American实现类我们不做改变,现在已不再需要ChinaCondition类和AmericanCondition类,我们直接构建ProfileCondition类:

@Configuration
public class ProfileConfig {
    @Bean("country")
    @Profile("中国")
    World china(){
        return new China();
    }

    @Bean("country")
    @Profile("美国")
    World american(){
        return new American();
    }
}

再配置一个运行主函数ProfileMain加载对应Bean:

public class ProfileMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext actx = new AnnotationConfigApplicationContext();
        actx.getEnvironment().setActiveProfiles("美国");
        actx.register(ProfileConfig.class);
        actx.refresh();

        World world = (World) actx.getBean("country");
        System.out.println(world.showName());
    }
}

效果和上面是一样的。

@Profile内部使用的也是@Conditional,只是他将matches函数中需要写的业务逻辑封装,我们直接使用就可以了。

总结

条件注解在 Spring 中的使用,它的一个核心思想就是当满足某种条件的时候,某个 Bean 才会生效,而正是这一特性,支撑起了 Spring Boot 的自动化配置。

参考资料:SpringBoot教程@江南一点雨

上一篇:PHP timezone_identifiers_list() 函数


下一篇:python的面型对象与实例6-类属性的增删改查