Spring註解之@Conditional

Lambert丶Shi發表於2020-10-13

前言

Spring4推出了@Conditional註解,方便程式根據當前環境或者容器情況來動態注入bean,SpingBoot在@Conditional的基礎上派生出許多註解,如@ConditionalOnMissingBean、@ConditionalOnExpression、@ConditionalOnClass等,這樣使得我們動態注入Bean更加簡潔方便,所以我覺得我們有必須來好好的學習一下@Conditional註解。

原始碼解析

  • @Conditional註解原始碼
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	Class<? extends Condition>[] value();

}

從這個註解的原始碼我們可以看出這個註解是作用在類上或者方法上的,並且@Conditional保留在執行時期,@Conditional註解只有一個value屬性,它是Condition的子類。

  • Condition原始碼
public interface Condition {

	/**
	 * Determine if the condition matches.
	 * @param context the condition context
	 * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
	 * or {@link org.springframework.core.type.MethodMetadata method} being checked.
	 * @return {@code true} if the condition matches and the component can be registered
	 * or {@code false} to veto registration.
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

  • 這是一個函式介面,因此可以用作lambda表示式或方法引用的賦值目標
  • 此介面是配合@Conditional註解使用
  • 這個Condition介面只有matches一個方法,從matches方法的註釋中,得知這個介面的作用就是判斷條件是否匹配返回true或false,如果返回成功就註冊Bean,否則就不註冊
  • matches方法的兩個引數
  1. context :環境條件(根據環境判斷是否需要註冊Bean)
  2. metadata:被檢查的類或方法的後設資料(被@Conditional標註的方法或類的後設資料)

@Conditional工作流程

它的作用就是在需要註冊Bean的時候,就會檢查自身是否標註了@Conditional註解,如果標註@Conditional註解就會通過它的value屬性,進行判斷是否需要註冊Bean

@Conditaional實戰

我們來做個案例,開酒店需要營業執照,如果有營業執照就將Hotel注入Spring容器,如果沒有就拒絕注入。

  • 酒店實體類
/**
 * @author shiKui
 */
public class Hotel {
}

我們需要注入Spring容器中的實體類

  • 實現Condition
public class HotelCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String has = context.getEnvironment().getProperty("businessLicense");
        return "true".equals(has);
    }
}

實現Condition介面配合@Conditional一起使用,如果環境中的businessLicense(營業執照)為true則可以進行注入,否則反之。

  • 配置類
/**
 * @author shiKui
 */
@Configuration
public class HotelConditionConfig {
    @Conditional(value = HotelCondition.class)
    @Bean
    public Hotel hotel(){
        return new Hotel();
    }
}

注入Hotel物件到Spring容器中,但是使用了@Conditional,那麼會根據HotelConditionConfig中的matches的返回值是否注入Hotel物件

  • 測試類
public class ConditionTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.getEnvironment().getSystemProperties().put("businessLicense",true);
        applicationContext.register(HotelConditionConfig.class);
        applicationContext.refresh();
        String[] beanNamesForType = applicationContext.getBeanNamesForType(Hotel.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
    }
}

通過無參構造方法建立AnnotationConfigApplicationContext 物件,並在Spring的上下文環境中新增businessLicense(營業執照)為true,然後載入容器,檢視Hotel是否注入容器中

  • 執行結果
    在這裡插入圖片描述
    我們可以看到hotel成功注入了。@Condition也可以作用於方法之上,但是使用方法還是一樣的。
    至此相信大家對@Conditional註解也有一定的瞭解了。

相關文章