zoukankan      html  css  js  c++  java
  • @Conditional注解使用及@ConditionalOnXXX各注解的作用

    本文为博主原创,转载请注明 出处:

    一。@Conditional注解作用:

        必须是 @Conditional 注解指定的条件成立,才会在容器中添加组件,配置类里面的所有配置才会生效

    二。@Conditional 衍生注解

    @Conditional扩展注解作用 判断是否满足指定条件
    @ConditionalOnBean 容器中存在指定Bean
    @ConditionalOnMissingBean 容器中不存在指定Bean;
    @ConditionalOnClass 系统中有指定的类
    @ConditionalOnMissingClass 系统中没有指定的类
    @ConditionalOnProperty 系统中指定的属性是否有指定的值
    @ConditionalOnResource 类路径下是否存在指定资源文件
    @ConditionalOnWebApplication 当前是web环境

    三。@Conditional注解 的使用 

      3.1 @Conditional 注解源码解析

        @Conditional 注解源码:

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

        通过源码可以发现看到该注解的传参值 为一个数组,并且需要继承 Condition 类。

        查看 Condition 类的源码:

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

        Condition 为一个函数式接口,其中只有一个matches 方法,接口的返回类型为boolean 值,通过该boolean 值控制是否加载配置。

      3.2 @Conditional  实现控制bean 加载

        1. 创建一个bean的实体类:

    @Data
    @AllArgsConstructor
    public class Person {
    
        private String name;
    
        private int age;
    }

        2. 通过 @Configuration 注解定义两个person 的bean

    @Configuration
    public class BeanConfiguration {
        @Bean(name= "java")
        public Person person1(){
            return new Person("java",12);
        }
        @Bean(name= "linux")
        public Person person2(){
            return new Person("linux",22);
        }
    }

        3. 通过单元测试查看两个bean 

    @SpringBootTest
    class TestApplicationTests {
        @Autowired
        private ApplicationContext applicationContext;
    
        @Test
        void contextLoads() {
            Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class);
            personBeanMap.forEach((beanName, beanValue) -> {
                System.out.println(beanName + "--" + beanValue);
            });
        }
    }

        通过这个单元测试会打印出两行Person bean 的信息

        4. 定义 实现 Condition 接口的类,并控制是否加载。

    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.env.Environment;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class WindowsCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Environment environment = conditionContext.getEnvironment();
            String property = environment.getProperty("os.name");
            if (property.contains("linux")){
                return true;
            }
            return false;
        }
    }

        并在定义Bean 的BeanConfiguration 类中使用 @Condition 注解实现bean 是否加载

    import com.example.test.entity.Person;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class BeanConfiguration {
    
        @Bean(name= "java")
        public Person person1(){
            return new Person("java",12);
        }
    
        @Conditional(WindowsCondition.class)
        @Bean(name= "linux")
        public Person person2(){
            return new Person("linux",22);
        }
    }

        5.执行单元测试:

    import com.example.test.entity.Person;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.context.ApplicationContext;
    
    import java.util.Map;
    
    @SpringBootTest
    class TestApplicationTests {
        @Autowired
        private ApplicationContext applicationContext;
    
        @Test
        void contextLoads() {
            Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class);
            personBeanMap.forEach((beanName, beanValue) -> {
                System.out.println(beanName + "--" + beanValue);
            });
        }
    }

        运行之后只会打印 person1 这个bean 的信息。

    四。@ConditionalOnProperty 注解的使用

        该注解经常用来管理配置文件中的某些配置开关,比如 中间件 通过这个配置判断是否进行加载。

        查看 @ConditionalOnProperty 注解源码

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import org.springframework.context.annotation.Conditional;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Documented
    @Conditional({OnPropertyCondition.class})
    public @interface ConditionalOnProperty {
        String[] value() default {};
    
        String prefix() default "";
    
        String[] name() default {};
    
        String havingValue() default "";
    
        boolean matchIfMissing() default false;
    }

        value : String数组 该属性与下面的 name 属性不可同时使用,当value所对应配置文件中的值为false时,注入不生效,不为fasle注入生效

        prefix  :配置文件中key的前缀,可与value 或 name 组合使用

          name  :与 value 作用一致

        havingValue  : 与value 或 name 组合使用,只有当value 或 name 对应的值与havingValue的值相同时,注入生效 

         matchIfMissing  :该属性为true时,配置文件中缺少对应的value或name的对应的属性值,也会注入成功

         使用示例:

    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ConditionalOnProperty(prefix = "redis.config",value = "enabled",havingValue = "true")
    public class RedisConfiguration {
    }

        在application.yml 配置文件配置:

    redis.config.enabled=true

        当 redis.config.enabled 值为 true时,会加载该类的配置,若只为false,则不加载。

        通过这种方式,可以很好的控制一些功能在不同环境上的开发性和使用性。

      

  • 相关阅读:
    Java邮件开发(JavaMail)
    SQL删除所有表和数据
    Hyper-V由于虚拟机监控程序未运行
    .NET CORE IIS PUT和DELETE请求失败 405
    ReSharper 快捷键调试
    hyper-v提示监控未运行
    c#定义Ilist集合
    WindowsFormsApp1设置开机自启动
    SQL查询总数和分页数
    EF执行SQL语句
  • 原文地址:https://www.cnblogs.com/zjdxr-up/p/15685923.html
Copyright © 2011-2022 走看看