一文了解@Conditional注解说明和使用

@Conditional:Spring4.0 介绍了一个新的注解@Conditional,它的逻辑语义能够做为"If…then…else…"来对bean的注册起做用。java

@Contidional 介绍

​ Conditional 是由 SpringFramework 提供的一个注解,位于 org.springframework.context.annotation 包内,定义以下。spring

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {
 
    Class<? extends Condition>[] value();
 
}

​ SpringBoot 模块大量的使用@Conditional 注释,咱们能够将Spring的@Conditional注解用于如下场景:数组

  • 能够做为类级别的注解直接或者间接的与@Component相关联,包括@Configuration类;
  • 能够做为元注解,用于自动编写构造性注解;
  • 做为方法级别的注解,做用在任何@Bean方法上。

Condition 接口

​ 咱们须要一个类实现Spring提供的Condition接口,它会匹配@Conditional所符合的方法,而后咱们可使用咱们在@Conditional注解中定义的类来检查。ide

public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Spring @Conditional注解实例

做用在方法上

​ 先来看一个简单一些的示例,咱们假设有三个角色老师Teacher、学生Student和父母Parent,三种环境Linux、Windows和MacOSX,若是是Linux环境,就注册Teacher,若是是Windows环境就注册Parent,若是是Mac 环境就注册Student。代码示例以下:测试

  • 首先建立Teacher和Student对象,没有任何的属性和方法,只是一个空类
//若是当前工程运行在Windows系统下,就注册Student
public class Student {}

//若是当前工程运行在Linux系统下,就注册Teacher
public class Teacher {}

// 若是是Mac OSX 系统,就注册Parent
public class Parent {}
  • 建立一个LinuxCondition和一个WindowsCondition,LinuxCondition可以匹配Linux环境,WindowsCondition可以匹配Windows环境,MacOSX 系统匹配mac环境。
public class LinuxCondition implements Condition {

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 获取系统环境的属性
          String systemName = context.getEnvironment().getProperty("os.name");
          if(systemName.contains("Linux")){
              return true;
          }
          return false;
    }
}

//自定义一个判断条件
public class WindowsCondition implements Condition {

    /*
     * ConditionContext context: spring容器上下文环境
     * AnnotatedTypeMetadata metadata :@Conditional修饰类型信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            
           String systemName = context.getEnvironment().getProperty("os.name");
           if(systemName.contains("Windows")){
               return true;
           }
        return false;
    }

}

public class OsxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
        if(property.equals("Mac OS X")){
            return true;
        }
        return false;
    }
}
  • 下面来新建匹配注册环境,若是系统是Linux环境,就注册Teacher,若是系统是Windows,就注册Parent,若是是Mac 系统,就注册Student
@Configuration
public class AppConfig {

    @Conditional(OsxCondition.class)
    @Bean
    public Student student(){
        return new Student();
    }

    @Conditional(LinuxCondition.class)
    @Bean
    public Teacher teacher(){
        return new Teacher();
    }

    @Conditional(WindowsCondition.class)
    @Bean
    public Parent parent(){
        return new Parent();
    }
}
  • 新建测试类进行测试
public class ConditionTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for(String name : names){
            System.out.println("name = " + name);
        }
    }
}

由输出能够看出,name = student 被输出到控制台,也就是说,我当前所用的系统环境是MacOSX环境,因此注册的是OSXCondition,也就是student的bean。.net

手动设置系统环境

也能够进行手动修改vm.options,把当前的系统环境变为Linux 或者Windows,以Idea为例:code

Edit Configurations中找到vm.options 选项,把系统环境改成 Linux,以下:对象

而后从新启动测试,发现Teacher 被注入进来了,修改当前环境为Windows,观察Parent也被注入进来并输出了。blog

做用在类上

​ @Conditional 注解能够做用在类上,表示此类下面全部的bean知足条件后均可以进行注入,一般与@Configuration注解一块儿使用。接口

  • 新建一个AppClassConfig,在类上标注@Conditional()注解,并配置相关bean,以下:
@Conditional(value = OsxCondition.class)

上文表示若是是OsxCondition.class 的话,就注册student、teacher、parent

  • 测试类不用修改,直接用原测试类进行测试,发现student、 teacher、 parent 都被注册进来了

多个条件类

​ 由于@Conditional注解的value 方法默认传递一个数组,因此能够接受多个condition,为了测试以下状况,

新建一个 TestCondition类,以下:

// 单纯为了测试
public class TestCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 返回false,表示不匹配
        return false;
    }
}

修改一下AppClassConfig

@Conditional(value = {OsxCondition.class,TestCondition.class})

也就是给@Conditional 多加了一个参数 TestCondition.class

启动以前的测试类,发现上述的bean都没有注入,也就是说,只有在知足OsxCondition.class 和 TestCondition.class 都为true的状况下,才会注入对应的bean,修改TestCondition.class的matches方法的返回值为true,从新观察返回结果,发现上述bean都被注入了。

@Conditional 与@Profile 的对比

​ @Spring3.0 也有一些和@Conditional 类似的注解,它们是Spring SPEL 表达式和Spring Profiles 注解 Spring4.0的@Conditional 注解要比@Profile 注解更加高级。@Profile 注解用来加载应用程序的环境。@Profile注解仅限于根据预约义属性编写条件检查。 @Conditional注释则没有此限制。

​ Spring中的@Profile 和 @Conditional 注解用来检查"If…then…else"的语义。然而,Spring4 @Conditional是@Profile 注解的更通用法。

  • Spring 3中的 @Profiles仅用于编写基于Environment变量的条件检查。 配置文件可用于基于环境加载应用程序配置。
  • Spring 4 @Conditional注解容许开发人员为条件检查定义用户定义的策略。 @Conditional可用于条件bean注册。

文章参考:

https://blog.csdn.net/xcy1193068639/article/details/81491071

相关文章
相关标签/搜索