zoukankan      html  css  js  c++  java
  • 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)
    
  • 相关阅读:
    Oracle 按一行里某个字段里的值分割成多行进行展示
    Property or method "openPageOffice" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by
    SpringBoot 项目启动 Failed to convert value of type 'java.lang.String' to required type 'cn.com.goldenwater.dcproj.dao.TacPageOfficePblmListDao';
    Maven 设置阿里镜像
    JS 日期格式化,留作参考
    JS 过滤数组里对象的某个属性
    原生JS实现简单富文本编辑器2
    Chrome控制台使用详解
    android权限(permission)大全
    不借助第三方网站四步实现手机网站转安卓APP
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/11020434.html
Copyright © 2011-2022 走看看