目录

一、概述

二、举例

三 、根据条件注入容器

1. 标注在方法上

2. 标注在类上

3. 多个条件类若

本文讲解有描述错误之处,或者有错别字,欢迎指正,希望大家毫不吝啬。

一、概述

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。

@Conditional的定义

//此注解可以标注在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

从代码中可以看到,需要传入一个Class数组,并且需要继承Condition接口:

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

Condition是个接口,需要实现matches方法,返回true则注入bean,false则不注入

 

二、举例

1. 创建 PersonEntity类

public class PersonEntity {

    private String userName;
    private Integer age;

    public PersonEntity() { }

    public PersonEntity(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
    }

    @Override
    public String toString() {
        return "PersonEntity{" +
                "userName='" + userName + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

 

2. 创建BeanConfiguration类

   用于配置两个 PersonEntity 实例并注入,一个是比尔盖茨,一个是林纳斯

@Configuration
public class BeanConfiguration {

    @Bean(name = "bill")
    protected PersonEntity getBillInfo(){

        return new PersonEntity("bill",38);
    }

    @Bean("linus")
    protected PersonEntity getBinusInfo(){

        return new PersonEntity("linus",58);
    }

}

 

3. 测试类进行验证这两个Bean是否注入成功

public class ConditionalTest {

    private static AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfiguration.class);


    @Test
    public void test1(){

        Map<String, PersonEntity> map = applicationContext.getBeansOfType(PersonEntity.class);
        System.out.println(map);

    }
}

 运行,输出结果是这样的,两个PersonEntity实例被注入进容器

spring clod 怎么配置国际化 spring @conditional_条件注入

三 、根据条件注入容器

这是一个简单的例子,现在问题来了,如果我想根据当前操作系统来注入PersonEntity实例Windows下注入bill,Linux下注入linus,怎么实现呢?

这就需要我们用到@Conditional注解了,前言中提到,需要实现Condition接口,并重写方法来自定义match规则。

1. 创建一个WindowsCondition类

public class WindowsCondition implements Condition {

    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     * */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取ioc使用的beanFactory
//        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
//        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取bean定义的注册类
//        BeanDefinitionRegistry registry = conditionContext.getRegistry();

        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //获得当前系统环境
        String property = environment.getProperty("os.name");
        //包含Windows则说明是windows系统,返回true
        if (property.contains("Windows")){
            return true;
        }
        return false;
    }
}

 matches方法的两个参数的意思在注释中讲述了,值得一提的是,conditionContext提供了多种方法,方便获取各种信息,也是SpringBoot中 @ConditonalOnxx注解多样扩展的基础。

2. 创建LinuxCondition类

public class LinuxCondition implements Condition {

    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     * */
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        // 获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        // 获得当前系统环境
        String property = environment.getProperty("os.name");
        // 包含Windows则说明是windows系统,返回true
        if (property.contains("Linux")){
            return true;
        }
        // 放弃注入
        return false;
    }
}

 

3.测试条件注入容器

接着就是使用这两个类了,因为此注解可以标注在方法上和类上,所以分开测试

1. 标注在方法上

修改BeanConfig

@Configuration
public class BeanConfiguration {

    //如果WindowsCondition的实现方法返回true,则注入这个bean
    @Conditional(WindowsCondition.class)
    @Bean(name = "bill")
    protected PersonEntity getBillInfo(){

        return new PersonEntity("bill",38);
    }

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    protected PersonEntity getBinusInfo(){

        return new PersonEntity("linus",58);
    }

}

 

修改测试方法,使其可以打印当前系统名:

@Test
    public void test1(){
        
        String osName = applicationContext.getEnvironment().getProperty("os.name");
        System.out.println("当前系统为:" + osName);
        Map<String, PersonEntity> map = applicationContext.getBeansOfType(PersonEntity.class);
        System.out.println(map);

    }

 

运行结果如下

spring clod 怎么配置国际化 spring @conditional_Windows_02

我是运行在windows上的所以只注入了bill,嗯,没毛病!

接着实验linux下的情况,不能运行在linux下,但可以修改运行时参数:

-Dos.name=Linux

spring clod 怎么配置国际化 spring @conditional_Windows_03

 

修改后启动测试方法

spring clod 怎么配置国际化 spring @conditional_Conditional_04

 一个方法只能注入一个bean实例,所以@Conditional标注在方法上只能控制一个Bean实例是否注入

2. 标注在类上

一个类中可以注入很多实例,@Conditional标注在类上就决定了一批Bean是否注入。

我们试一下,将BeanConfiguration改写,这时,如果WindowsCondition返回true,则两个PersonEntity实例将被注入(注意:上一个测试将os.name改为linux,这是我将把这个参数去掉):

@Conditional(WindowsCondition.class)
@Configuration
public class BeanConfiguration {


    @Bean(name = "bill")
    protected PersonEntity getBillInfo(){

        return new PersonEntity("bill",38);
    }

    @Bean("linus")
    protected PersonEntity getBinusInfo(){

        return new PersonEntity("linus",58);
    }

}

 

结果两个实例都被注入

spring clod 怎么配置国际化 spring @conditional_Conditional_05

如果将类上的WindowsCondition.class改为LinuxCondition.class,结果应该可以猜到:

spring clod 怎么配置国际化 spring @conditional_Spring_06

结果就是空的,类中所有bean都没有注入

3. 多个条件类

前言中说,@Conditional 注解传入的是一个Class数组,存在多种条件类的情况。

这种情况貌似判断难度加深了,测试一波,新增新的条件类,实现的matches返回false(这种写死返回false的方法纯属测试用,没有实际意义O(∩_∩)O)

public class ObstinateCondition implements Condition {

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}

BeanConfiguration修改一下

@Conditional({WindowsCondition.class,ObstinateCondition.class})
@Configuration
public class BeanConfiguration {


    @Bean(name = "bill")
    protected PersonEntity getBillInfo(){

        return new PersonEntity("bill",38);
    }

    @Bean("linus")
    protected PersonEntity getBinusInfo(){

        return new PersonEntity("linus",58);
    }

}

控制台输入

spring clod 怎么配置国际化 spring @conditional_Conditional_07

现在如果将ObstinateCondition的matches方法返回值改成true,两个bean就被注入进容器:

spring clod 怎么配置国际化 spring @conditional_spring clod 怎么配置国际化_08

结论

第一个条件类实现的方法返回true,第二个返回false,则结果false,不注入进容器。

第一个条件类实现的方法返回true,第二个返回true,则结果true,注入进容器中。