• Spring 注解之 @Conditional


    一、@Conditional 注解简介

    @Conditional 注解是 Spring4 新提供的注解,它的作用是按照一定的条件进行判断,如果满足条件给 IOC 容器注入相应的 bean 

    @Conditional 注解源码如下:

    // 该注解可以标注在 类、接口、枚举声明、方法上
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
    	// @Conditional 注解只有一个属性值 value ,它的类型是一个 Class[]
    	// 该数组中的元素是 Condition 的一个子类
    	Class<? extends Condition>[] value();
    }
    

     我们点开 Condition 进去看一下它到底是什么

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

    点开之后发现它是一个接口,并且有一个 matches(...) 的方法,该方法的返回值如果是 true,则判断条件成立,反之,则条件不成立.这样就很明确了,原来 @Conditional() 注解中的属性值是一个 Class 类型的数组,并且该数组中的元素就是 Condition 的实现类

    类似于这样 @Conditional({A.class,B.class,C.class})  (注: 这里的类 A、B、C 是 Condition 的实现类)

     

    二、现有需求:通过操作系统作为条件来筛选注册对象

    1、编写自定义类 WindowsCondition 实现 Condition 接口

    public class WindowsCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 获取环境信息
            Environment environment = context.getEnvironment();
            // 获取操作系统信息
            String property = environment.getProperty("os.name");
            // 如果操作系统信息中包含 Windows ,那么返回 true,也就是判断条件成立
            if(property.contains("Windows")){
                return true;
            }
            return false;
        }
    }

    2、编写自定义类 LinuxCondition 实现 Condition 接口

    public class LinuxCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment environment = context.getEnvironment();
            String property = environment.getProperty("os.name");
            if(property.contains("Linux")){
                return true;
            }
            return false;
        }
    }

    3、配置类

    @Configuration
    public class SpringConfiguration {
        @Bean("bill")
    	// 如果只有一个参数,那么 {} 可以省略
        @Conditional({WindowsCondition.class})
        public Person person01() {
            return new Person("Bill Gates", 66);
        }
    
        @Bean("linus")
        @Conditional(LinuxCondition.class)
        public Person person02() {
            return new Person("Linus Torvalds", 44);
        }
    }

    4、测试类

    public class SpringTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
            String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
        }
    }

    5、测试结果

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalRequiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    // 配置类
    springConfiguration
    // 由于本机操作系统是 Windows8.1 ,可以看到 linus 没有注册进 Spring 容器
    bill

    6、更换一下虚拟机参数,切换为 Linux 环境,看一下测试结果

    Run---->Edit Configurations----> -Dos.name=Linux

    再次启动项目测试结果如下:

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalRequiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    springConfiguration
    // linus 这个 bean 就注入了 Spring 容器中,而 bill 就没有注入进来
    linus
    

      

    三、@Conditional 注解标注位置

    通过上面的例子我们可以看到,我们都是将 @Conditional 注解标注在了方法上面,但是我们查看源码的时候可以知道,该注解不但可以标注在方法上,还可以标注在类、接口、枚举声明上面,那么标注在其它地方的时候代表的意思又是什么呢?

    1、标注在方法上:由于一个方法只能注入一个 bean 实例,所以 @Conditional 注解标注在方法上只能控制一个 bean 实例是否注入

    2、标注在类上:一个类上可以注入很多的 bean 实例,所以 @Conditional 注解标注在类上就能控制一批 bean 实例是否注入

    自己测试了一下,结论如下:

    @Conditional({A.class,B.class,C.class,D.class...})
    @Configuration
    public class SpringConfiguration {
    	......
    }

    A、B、C、D、....都是 Condition 接口的实现类,如果它们中有一个类的  matches(...) 方法返回值为 false,那么该配置类所有的 bean 都不会注入到 spring 容器中,只有所有类的 matches(...) 方法返回值为 true,那么该配置类才生效

    个人猜测,标注在类上的 @Conditional 注解的判断条件为 false,那么整个类所有执行的行为将失效.(我们这里是注入容器的行为,这个以后看了源码再来验证.)

      

     

  • 相关阅读:
    Windows系统CMD窗口下,MySQL建库、还原数据库命令操作示例
    Java JPA 报java.lang.IllegalArgumentException: Validation failed for query for method public abstract ...异常的一种原因和解决办法
    MySQL 5.7 执行SQL报错:1055
    Java8使用实现Runnable接口方式创建新线程的方法
    模板方法模式
    策略模式
    观察者模式
    装饰器模式
    原型模式
    单例模式
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/13538584.html
Copyright © 2020-2023  润新知