Spring 注解之 @Conditional

一、@Conditional 注解简介

@Conditional 注解是 Spring4 新提供的注解,它的作用是按照一定的条件进行判断,如果满足条件给 IOC 容器注入相应的 bean 

@Conditional 注解源码如下:

// 该注解可以标注在 类、接口、枚举声明、方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	// @Conditional 注解只有一个属性值 value ,它的类型是一个 Class[]
	// 该数组中的元素是 Condition 的一个子类
	Class<? extends Condition>[] value();
}

 我们点开 Condition 进去看一下它到底是什么

public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

点开之后发现它是一个接口,并且有一个 matches(...) 的方法,该方法的返回值如果是 true,则判断条件成立,反之,则条件不成立.这样就很明确了,原来 @Conditional() 注解中的属性值是一个 Class 类型的数组,并且该数组中的元素就是 Condition 的实现类

类似于这样 @Conditional({A.class,B.class,C.class})  (注: 这里的类 A、B、C 是 Condition 的实现类)

 

二、现有需求:通过操作系统作为条件来筛选注册对象

1、编写自定义类 WindowsCondition 实现 Condition 接口

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取环境信息
        Environment environment = context.getEnvironment();
        // 获取操作系统信息
        String property = environment.getProperty("os.name");
        // 如果操作系统信息中包含 Windows ,那么返回 true,也就是判断条件成立
        if(property.contains("Windows")){
            return true;
        }
        return false;
    }
}

2、编写自定义类 LinuxCondition 实现 Condition 接口

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Linux")){
            return true;
        }
        return false;
    }
}

3、配置类

@Configuration
public class SpringConfiguration {
    @Bean("bill")
	// 如果只有一个参数,那么 {} 可以省略
    @Conditional({WindowsCondition.class})
    public Person person01() {
        return new Person("Bill Gates", 66);
    }

    @Bean("linus")
    @Conditional(LinuxCondition.class)
    public Person person02() {
        return new Person("Linus Torvalds", 44);
    }
}

4、测试类

public class SpringTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

5、测试结果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
// 配置类
springConfiguration
// 由于本机操作系统是 Windows8.1 ,可以看到 linus 没有注册进 Spring 容器
bill

6、更换一下虚拟机参数,切换为 Linux 环境,看一下测试结果

Run---->Edit Configurations----> -Dos.name=Linux

再次启动项目测试结果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfiguration
// linus 这个 bean 就注入了 Spring 容器中,而 bill 就没有注入进来
linus

  

三、@Conditional 注解标注位置

通过上面的例子我们可以看到,我们都是将 @Conditional 注解标注在了方法上面,但是我们查看源码的时候可以知道,该注解不但可以标注在方法上,还可以标注在类、接口、枚举声明上面,那么标注在其它地方的时候代表的意思又是什么呢?

1、标注在方法上:由于一个方法只能注入一个 bean 实例,所以 @Conditional 注解标注在方法上只能控制一个 bean 实例是否注入

2、标注在类上:一个类上可以注入很多的 bean 实例,所以 @Conditional 注解标注在类上就能控制一批 bean 实例是否注入

自己测试了一下,结论如下:

@Conditional({A.class,B.class,C.class,D.class...})
@Configuration
public class SpringConfiguration {
	......
}

A、B、C、D、....都是 Condition 接口的实现类,如果它们中有一个类的  matches(...) 方法返回值为 false,那么该配置类所有的 bean 都不会注入到 spring 容器中,只有所有类的 matches(...) 方法返回值为 true,那么该配置类才生效

个人猜测,标注在类上的 @Conditional 注解的判断条件为 false,那么整个类所有执行的行为将失效.(我们这里是注入容器的行为,这个以后看了源码再来验证.)

  

 

原文地址:https://www.cnblogs.com/xiaomaomao/p/13538584.html