zoukankan      html  css  js  c++  java
  • 【转】 SpringBoot(15)—@Conditional注解

    【转】 SpringBoot(15)—@Conditional注解

    SpringBoot(15)—@Conditional注解

    作用 @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件的才给容器注册Bean。

    一、概述

    1、@Conditional注解定义

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

    2、Condition

    我们点进去看后,发现它是一个接口,有一个方法。

    @FunctionalInterface
    public interface Condition {
        boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
    }
    

    3、ConditionContext

    它持有不少有用的对象,可以用来获取很多系统相关的信息,来丰富条件判断,接口定义如下

    public interface ConditionContext {
        /**
         * 获取Bean定义
         */
        BeanDefinitionRegistry getRegistry();
        /**
         * 获取Bean工程,因此就可以获取容器中的所有bean
         */
        @Nullable
        ConfigurableListableBeanFactory getBeanFactory();
        /**
         * environment 持有所有的配置信息
         */
        Environment getEnvironment();
        /**
         * 资源信息
         */
        ResourceLoader getResourceLoader();
        /**
         * 类加载信息
         */
        @Nullable
        ClassLoader getClassLoader();
    }
    

    二、案例

    需求 根据当前系统环境的的不同实例不同的Bean,比如现在是Mac那就实例一个Bean,如果是Window系统实例另一个Bean。

    1、SystemBean

    首先创建一个Bean类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class SystemBean {
        /**
         * 系统名称
         */
        private String systemName;
        /**
         * 系统code
         */
        private String systemCode;
    }
    

    2、通过Configuration配置实例化Bean

    @Slf4j
    @Configuration
    public class ConditionalConfig {
        /**
         * 如果WindowsCondition的实现方法返回true,则注入这个bean
         */
        @Bean("windows")
        @Conditional({WindowsCondition.class})
        public SystemBean systemWi() {
            log.info("ConditionalConfig方法注入 windows实体");
            return new SystemBean("windows系统","002");
        }
        /**
         * 如果LinuxCondition的实现方法返回true,则注入这个bean
         */
        @Bean("mac")
        @Conditional({MacCondition.class})
        public SystemBean systemMac() {
            log.info("ConditionalConfig方法注入 mac实体");
            return new SystemBean("Mac ios系统","001");
        }
    }
    

    3、WindowsCondition和MacCondition

    这两个类都实现了Condition接口, 只有matches方法返回true才会实例化当前Bean

    1)WindowsCondition

    @Slf4j
    public class WindowsCondition implements Condition {
        /**
         * @param conditionContext:判断条件能使用的上下文环境
         * @param annotatedTypeMetadata:注解所在位置的注释信息
         */
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            //获取ioc使用的beanFactory
            ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
            //获取类加载器
            ClassLoader classLoader = conditionContext.getClassLoader();
            //获取当前环境信息
            Environment environment = conditionContext.getEnvironment();
            //获取bean定义的注册类
            BeanDefinitionRegistry registry = conditionContext.getRegistry();
            //获得当前系统名
            String property = environment.getProperty("os.name");
            //包含Windows则说明是windows系统,返回true
            if (property.contains("Windows")){
                log.info("当前操作系统是:Windows");
                return true;
            }
            return false;
        }
    }
    

    2) MacCondition

    @Slf4j
    public class MacCondition implements Condition {
    
       @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Environment environment = conditionContext.getEnvironment();
            String property = environment.getProperty("os.name");
            if (property.contains("Mac")) {
                log.info("当前操作系统是:Mac OS X");
                return true;
            }
            return false;
        }
    }
    

    4、测试类测试

    /**
     * @author xub
     * @date 2019/6/13 下午10:42
     */
    @SpringBootTest(classes = Application.class)
    @RunWith(SpringRunner.class)
    public class TestConditionOn {
    
        @Autowired
        private SystemBean windows;
        @Autowired
        private SystemBean mac;
    
        @Test
        public void test() {
            if (windows != null) {
                System.out.println("windows = " + windows);
            }
            if (mac != null) {
                System.out.println("linux = " + mac);
            }
        }
    }
    

    运行结果

    通过运行结果可以看出

    1、虽然配置两个Bean,但这里只实例化了一个Bean,因为我这边是Mac电脑,所以实例化的是mac的SystemBean

    2、注意一点,我们可以看出 window并不为null,而是mac实例化的Bean。说明 只要实例化一个Bean的,不管你命名什么,都可以注入这个Bean。

    修改一下

    这里做一个修改,我们把ConditionalConfig中的这行代码注释掉。

    // @Conditional({WindowsCondition.class})
    

    再运行下代码

    通过运行结果可以看出,配置类的两个Bean都已经注入成功了。

    注意 当同一个对象被注入两次及以上的时候,那么你在使用当前对象的时候,名称一定要是两个bean名称的一个,否则报错。比如修改为

        @Autowired
        private SystemBean windows;
        @Autowired
        private SystemBean mac;
        @Autowired
        private SystemBean linux;
    

    在启动发现,报错了。

    意思很明显,就是上面只实例化成功一个SystemBean的时候,你取任何名字,反正就是把当前已经实例化的对象注入给你就好了。
    但是你现在同时注入了两个SystemBean,你这个时候有个名称为linux,它不知道应该注入那个Bean,所以采用了报错的策略。

    GitHub源码 https://github.com/yudiandemingzi/spring-boot-study

    项目名称 03-conditional


    ### 参考

    1、Spring @Conditional注解


    只要自己变优秀了,其他的事情才会跟着好起来(中将3)
    
  • 相关阅读:
    【Redfin SDE intern】跪经
    刷题upupup【Java中Queue、Stack、Heap用法总结】
    刷题upupup【Java中HashMap、HashSet用法总结】
    【lintcode】二分法总结 II
    【lintcode】 二分法总结 I
    201671010117 2016-2017-2 《Java程序设计》面向对象程序设计课程学习进度条
    201671010117 2016-2017-2《Java程序设计》第十八周学习心得
    201671010117 2016-2017-2 《Java程序设计》Java第十七周学习心得
    201671010117 2016-2017-2 《JAVA程序设计》java第十六周学习心得
    201671010117 2016-2017-2 《JAVA程序设计》java第十五周学习心得
  • 原文地址:https://www.cnblogs.com/Javastudy-note/p/13818097.html
Copyright © 2011-2022 走看看