一文了解@Conditional註解說明和使用

@Conditional:Spring4.0 介紹了一個新的註解@Conditional,它的邏輯語義能夠做爲"If…then…else…"來對bean的註冊起做用。java

@Contidional 介紹

​ Conditional 是由 SpringFramework 提供的一個註解,位於 org.springframework.context.annotation 包內,定義以下。spring

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

​ SpringBoot 模塊大量的使用@Conditional 註釋,咱們能夠將Spring的@Conditional註解用於如下場景:數組

  • 能夠做爲類級別的註解直接或者間接的與@Component相關聯,包括@Configuration類;
  • 能夠做爲元註解,用於自動編寫構造性註解;
  • 做爲方法級別的註解,做用在任何@Bean方法上。

Condition 接口

​ 咱們須要一個類實現Spring提供的Condition接口,它會匹配@Conditional所符合的方法,而後咱們可使用咱們在@Conditional註解中定義的類來檢查。ide

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

Spring @Conditional註解實例

做用在方法上

​ 先來看一個簡單一些的示例,咱們假設有三個角色老師Teacher、學生Student和父母Parent,三種環境Linux、Windows和MacOSX,若是是Linux環境,就註冊Teacher,若是是Windows環境就註冊Parent,若是是Mac 環境就註冊Student。代碼示例以下:測試

  • 首先建立Teacher和Student對象,沒有任何的屬性和方法,只是一個空類
//若是當前工程運行在Windows系統下,就註冊Student
public class Student {}

//若是當前工程運行在Linux系統下,就註冊Teacher
public class Teacher {}

// 若是是Mac OSX 系統,就註冊Parent
public class Parent {}
  • 建立一個LinuxCondition和一個WindowsCondition,LinuxCondition可以匹配Linux環境,WindowsCondition可以匹配Windows環境,MacOSX 系統匹配mac環境。
public class LinuxCondition implements Condition {

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 獲取系統環境的屬性
          String systemName = context.getEnvironment().getProperty("os.name");
          if(systemName.contains("Linux")){
              return true;
          }
          return false;
    }
}

//自定義一個判斷條件
public class WindowsCondition implements Condition {

    /*
     * ConditionContext context: spring容器上下文環境
     * AnnotatedTypeMetadata metadata :@Conditional修飾類型信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            
           String systemName = context.getEnvironment().getProperty("os.name");
           if(systemName.contains("Windows")){
               return true;
           }
        return false;
    }

}

public class OsxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
        if(property.equals("Mac OS X")){
            return true;
        }
        return false;
    }
}
  • 下面來新建匹配註冊環境,若是系統是Linux環境,就註冊Teacher,若是系統是Windows,就註冊Parent,若是是Mac 系統,就註冊Student
@Configuration
public class AppConfig {

    @Conditional(OsxCondition.class)
    @Bean
    public Student student(){
        return new Student();
    }

    @Conditional(LinuxCondition.class)
    @Bean
    public Teacher teacher(){
        return new Teacher();
    }

    @Conditional(WindowsCondition.class)
    @Bean
    public Parent parent(){
        return new Parent();
    }
}
  • 新建測試類進行測試
public class ConditionTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for(String name : names){
            System.out.println("name = " + name);
        }
    }
}

由輸出能夠看出,name = student 被輸出到控制檯,也就是說,我當前所用的系統環境是MacOSX環境,因此註冊的是OSXCondition,也就是student的bean。.net

手動設置系統環境

也能夠進行手動修改vm.options,把當前的系統環境變爲Linux 或者Windows,以Idea爲例:code

Edit Configurations中找到vm.options 選項,把系統環境改成 Linux,以下:對象

而後從新啓動測試,發現Teacher 被注入進來了,修改當前環境爲Windows,觀察Parent也被注入進來並輸出了。blog

做用在類上

​ @Conditional 註解能夠做用在類上,表示此類下面全部的bean知足條件後均可以進行注入,一般與@Configuration註解一塊兒使用。接口

  • 新建一個AppClassConfig,在類上標註@Conditional()註解,並配置相關bean,以下:
@Conditional(value = OsxCondition.class)

上文表示若是是OsxCondition.class 的話,就註冊student、teacher、parent

  • 測試類不用修改,直接用原測試類進行測試,發現student、 teacher、 parent 都被註冊進來了

多個條件類

​ 由於@Conditional註解的value 方法默認傳遞一個數組,因此能夠接受多個condition,爲了測試以下狀況,

新建一個 TestCondition類,以下:

// 單純爲了測試
public class TestCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 返回false,表示不匹配
        return false;
    }
}

修改一下AppClassConfig

@Conditional(value = {OsxCondition.class,TestCondition.class})

也就是給@Conditional 多加了一個參數 TestCondition.class

啓動以前的測試類,發現上述的bean都沒有注入,也就是說,只有在知足OsxCondition.class 和 TestCondition.class 都爲true的狀況下,纔會注入對應的bean,修改TestCondition.class的matches方法的返回值爲true,從新觀察返回結果,發現上述bean都被注入了。

@Conditional 與@Profile 的對比

​ @Spring3.0 也有一些和@Conditional 類似的註解,它們是Spring SPEL 表達式和Spring Profiles 註解 Spring4.0的@Conditional 註解要比@Profile 註解更加高級。@Profile 註解用來加載應用程序的環境。@Profile註解僅限於根據預約義屬性編寫條件檢查。 @Conditional註釋則沒有此限制。

​ Spring中的@Profile 和 @Conditional 註解用來檢查"If…then…else"的語義。然而,Spring4 @Conditional是@Profile 註解的更通用法。

  • Spring 3中的 @Profiles僅用於編寫基於Environment變量的條件檢查。 配置文件可用於基於環境加載應用程序配置。
  • Spring 4 @Conditional註解容許開發人員爲條件檢查定義用戶定義的策略。 @Conditional可用於條件bean註冊。

文章參考:

https://blog.csdn.net/xcy1193068639/article/details/81491071

相關文章
相關標籤/搜索