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)
相關文章
相關標籤/搜索