SpringBoot(15)—@Conditional注解

SpringBoot(15)—@Conditional注解

做用 @Conditional是Spring4新提供的注解,它的做用是按照必定的条件进行判断,知足条件的才给容器注册Bean。java

1、概述

一、@Conditional注解定义

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

二、Condition

咱们点进去看后,发现它是一个接口,有一个方法。linux

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

三、ConditionContext

它持有很多有用的对象,能够用来获取不少系统相关的信息,来丰富条件判断,接口定义以下ios

public interface ConditionContext {
    /**
     * 获取Bean定义
     */
    BeanDefinitionRegistry getRegistry();
    /**
     * 获取Bean工程,所以就能够获取容器中的全部bean
     */
    @Nullable
    ConfigurableListableBeanFactory getBeanFactory();
    /**
     * environment 持有全部的配置信息
     */
    Environment getEnvironment();
    /**
     * 资源信息
     */
    ResourceLoader getResourceLoader();
    /**
     * 类加载信息
     */
    @Nullable
    ClassLoader getClassLoader();
}


2、案例

需求 根据当前系统环境的的不一样实例不一样的Bean,好比如今是Mac那就实例一个Bean,若是是Window系统实例另外一个Bean。git

一、SystemBean

首先建立一个Bean类github

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SystemBean {
    /**
     * 系统名称
     */
    private String systemName;
    /**
     * 系统code
     */
    private String systemCode;
}

二、经过Configuration配置实例化Bean

@Slf4j
@Configuration
public class ConditionalConfig {
    /**
     * 若是WindowsCondition的实现方法返回true,则注入这个bean
     */
    @Bean("windows")
    @Conditional({WindowsCondition.class})
    public SystemBean systemWi() {
        log.info("ConditionalConfig方法注入 windows实体");
        return new SystemBean("windows系统","002");
    }
    /**
     * 若是LinuxCondition的实现方法返回true,则注入这个bean
     */
    @Bean("mac")
    @Conditional({MacCondition.class})
    public SystemBean systemMac() {
        log.info("ConditionalConfig方法注入 mac实体");
        return new SystemBean("Mac ios系统","001");
    }
}

三、WindowsCondition和MacCondition

这两个类都实现了Condition接口, 只有matches方法返回true才会实例化当前Beanspring

1)WindowsConditionwindows

@Slf4j
public class WindowsCondition implements Condition {
    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //获取bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        //得到当前系统名
        String property = environment.getProperty("os.name");
        //包含Windows则说明是windows系统,返回true
        if (property.contains("Windows")){
            log.info("当前操做系统是:Windows");
            return true;
        }
        return false;
    }
}

2) MacConditionspringboot

@Slf4j
public class MacCondition implements Condition {

   @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Mac")) {
            log.info("当前操做系统是:Mac OS X");
            return true;
        }
        return false;
    }
}

四、测试类测试

/**
 * @author xub
 * @date 2019/6/13 下午10:42
 */
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class TestConditionOn {

    @Autowired
    private SystemBean windows;
    @Autowired
    private SystemBean mac;

    @Test
    public void test() {
        if (windows != null) {
            System.out.println("windows = " + windows);
        }
        if (mac != null) {
            System.out.println("linux = " + mac);
        }
    }
}

运行结果ide

经过运行结果能够看出测试

一、虽然配置两个Bean,但这里只实例化了一个Bean,由于我这边是Mac电脑,因此实例化的是mac的SystemBean

二、注意一点,咱们能够看出 window并不为null,而是mac实例化的Bean。说明 只要实例化一个Bean的,无论你命名什么,均可以注入这个Bean。

修改一下

这里作一个修改,咱们把ConditionalConfig中的这行代码注释掉。

// @Conditional({WindowsCondition.class})

再运行下代码

经过运行结果能够看出,配置类的两个Bean都已经注入成功了。

注意 当同一个对象被注入两次及以上的时候,那么你在使用当前对象的时候,名称必定要是两个bean名称的一个,不然报错。好比修改成

@Autowired
    private SystemBean windows;
    @Autowired
    private SystemBean mac;
    @Autowired
    private SystemBean linux;

在启动发现,报错了。

意思很明显,就是上面只实例化成功一个SystemBean的时候,你取任何名字,反正就是把当前已经实例化的对象注入给你就行了。
可是你如今同时注入了两个SystemBean,你这个时候有个名称为linux,它不知道应该注入那个Bean,因此采用了报错的策略。

GitHub源码 https://github.com/yudiandemingzi/SpringBootBlog

项目名称 03-conditional


参考

一、Spring @Conditional注解




只要本身变优秀了,其余的事情才会跟着好起来(中将3)
相关文章
相关标签/搜索