zoukankan      html  css  js  c++  java
  • Spring中的@conditional注解

     

    今天主要从以下几方面来介绍一下@Conditional注解

    • @Conditional注解是什么

    • @Conditional注解怎么使用

    1,@Conditional注解是什么

    @Conditional注解是可以根据一些自定义的条件动态的选择是否加载该bean到springIOC容器中去,如果看过springBoot源码的同学会发现,springBoot中大量使用了该注解

    2,@Conditional注解怎么使用

    查看@Conditional源码你会发现它既可以作用在方法上,同时也可以作用在上,源码如下:

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
        /**
         * All {@link Condition}s that must {@linkplain Condition#matches match}
         * in order for the component to be registered.
         */
        Class<? extends Condition>[] value();
    }

    设置给@conditional的类需要实现Condition接口

    我们看一下Condition的源码:

    public interface Condition {
        boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
    }
    
    ConditionContext源码:
    public interface ConditionContext {
        BeanDefinitionRegistry getRegistry();
    
        ConfigurableListableBeanFactory getBeanFactory();
    
        Environment getEnvironment();
    
        ResourceLoader getResourceLoader();
    
        ClassLoader getClassLoader();
    }
    AnnotatedTypeMetadata源码: 此类能够让我们检查带有@Bean注解的方法上还有其他什么注解
     public interface AnnotatedTypeMetadata { 

    boolean isAnnotated(String var1);
    Map<String, Object> getAnnotationAttributes(String var1);
    Map<String, Object> getAnnotationAttributes(String var1, boolean var2);
    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);
    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);
    }
    a,@Conditional作用在方法上

    定义一个Condition如下:

    /**
     * 定义一个bean的Condition
     *
     * @author zhangqh
     * @date 2018年5月1日
     */
    public class MyCondition implements Condition {
        public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata) {
            Environment env = context.getEnvironment();
            String system = env.getProperty("os.name");
            System.out.println("系统环境为 ==="+system);
            // 系统环境在Windows才加载该bean到容器中
            if(system.contains("Windows")){
                return true;
            }
            return false;
        }
    }

    定义一个bean加上@Conditional注解如下:

    @Conditional({MyCondition.class})
    @Bean(value="user1")
    public User getUser1(){
        System.out.println("创建user1实例");
        return new User("李四",26);
    }

    测试如下:

    AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] beanNames = applicationContext2.getBeanDefinitionNames();
    for(int i=0;i<beanNames.length;i++){
        System.out.println("bean名称为==="+beanNames[i]);
    }

    运行结果:

    bean名称为===mainConfig
    bean名称为===user0
    bean名称为===user1

    我这边电脑系统是window所以user1实例是有创建出来的,如果把MyCondition中的判断改成if(system.contains("linux"))那么user1是不会加载到spring容器中的

    b,@Conditional作用在类上

    修改注解配置如下:

    /**
     * 定义一个注解配置文件 必须要加上@Configuration注解
     *
     * @author zhangqh
     * @date 2018年4月30日
     */
    @Conditional({MyCondition.class})
    @Configuration
    public class MainConfig {
        /**
         * 定义一个bean对象
         * @return
         */
        @Scope
        @Lazy
        @Bean(value="user0")
        public User getUser(){
            System.out.println("创建user实例");
            return new User("张三",26);
        }
        //@Conditional({MyCondition.class})
        @Bean(value="user1")
        public User getUser1(){
            System.out.println("创建user1实例");
            return new User("李四",26);
        }
    }

    运行测试:

    bean名称为===mainConfig
    bean名称为===user0
    bean名称为===user1

    MainConfig中的bean都成功打印出来了,因为我MyCondition条件返回的是true,同样如果我修改成if(system.contains("linux"))那么MainConfig的bean就都不会实例化了

    c, @profile注解分析
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional({ProfileCondition.class})
    public @interface Profile {
        String[] value();
    }

    注意:@Profile本身也使用了@Condition注解,并且引用ProfileCondition作为Condition的实现。

    以下为ProfileCondition的实现

    class ProfileCondition implements Condition {
        ProfileCondition() {
        }
    
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            if (context.getEnvironment() != null) {
                MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
                if (attrs != null) {
                    Iterator var4 = ((List)attrs.get("value")).iterator();
    
                    Object value;
                    do {
                        if (!var4.hasNext()) {
                            return false;
                        }
    
                        value = var4.next();
                    } while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));
    
                    return true;
                }
            }
    
            return true;
        }
    }
    你所看得到的天才不过是在你看不到的时候还在努力罢了!
  • 相关阅读:
    用Latex编辑数学公式
    《利用Python进行数据分析》学习笔记之Matplotlib : pandas中的绘图函数
    《利用Python进行数据分析》学习笔记之Pandas基础
    splice()使用
    markdown语法
    【Docker】Docker 镜像
    【Docker】Docker 命令
    【Docker】Docker 安装
    【Docker】Docker 简介
    【MySQL 高级】知识拓展
  • 原文地址:https://www.cnblogs.com/heliusKing/p/10778107.html
Copyright © 2011-2022 走看看