Spring中的@conditional注解

Posted heliusking

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
    }
}

 

以上是关于Spring中的@conditional注解的主要内容,如果未能解决你的问题,请参考以下文章

Spring中的@conditional注解

详解Spring Boot框架中的@Conditional系列注解

详解Spring Boot框架中的@Conditional系列注解

spring in action学习笔记七:@Conditional注解的用法

Spring5源码深度分析之理解@Conditional,@Import注解

Spring条件注解@Conditional