国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解

這篇具有很好參考價值的文章主要介紹了【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

《Spring Boot 源碼學(xué)習(xí)系列》

【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解,開發(fā)框架-Spring Boot,spring boot,條件注解,Conditional,衍生注解

引言

前面的博文,Huazie 帶大家從 Spring Boot 源碼深入了解了自動配置類的讀取和篩選的過程,然后又詳解了OnClassCondition、 OnBeanCondition、OnWebApplicationCondition 這三個自動配置過濾匹配子類實現(xiàn)。

在上述的博文中,我們其實已經(jīng)初步涉及到了像 @ConditionalOnClass、@ConditionalOnBean、@ConditionalOnWebApplication 這樣的條件注解,并且這些條件注解里面,我們都能看到 @Conditional 注解。

【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解,開發(fā)框架-Spring Boot,spring boot,條件注解,Conditional,衍生注解

往期內(nèi)容

在開始本篇的內(nèi)容介紹之前,我們先來看看往期的系列文章【有需要的朋友,歡迎關(guān)注系列專欄】:

Spring Boot 源碼學(xué)習(xí)
Spring Boot 項目介紹
Spring Boot 核心運行原理介紹
【Spring Boot 源碼學(xué)習(xí)】@EnableAutoConfiguration 注解
【Spring Boot 源碼學(xué)習(xí)】@SpringBootApplication 注解
【Spring Boot 源碼學(xué)習(xí)】走近 AutoConfigurationImportSelector
【Spring Boot 源碼學(xué)習(xí)】自動裝配流程源碼解析(上)
【Spring Boot 源碼學(xué)習(xí)】自動裝配流程源碼解析(下)
【Spring Boot 源碼學(xué)習(xí)】深入 FilteringSpringBootCondition
【Spring Boot 源碼學(xué)習(xí)】OnClassCondition 詳解
【Spring Boot 源碼學(xué)習(xí)】OnBeanCondition 詳解
【Spring Boot 源碼學(xué)習(xí)】OnWebApplicationCondition 詳解

主要內(nèi)容

本篇我們重點介紹 @Conditional 條件注解,參見如下:

1. 初識 @Conditional

我們先來看看 @Conditional 注解的源碼【Spring Context 5.3.25】:

/**
 * 表示組件僅在所有指定條件匹配時才有資格注冊。
 * 
 * 條件是在bean定義即將注冊之前可以通過編程確定的任何狀態(tài)(有關(guān)詳細(xì)信息,請參閱Condition)。
 * 
 * @Conditional注解可以以以下任意方式使用:
 * 	作為類型級別的注釋直接或間接地應(yīng)用于帶有@Component的任何類,包括@Configuration類
 * 	作為元注釋,用于組合自定義注釋標(biāo)簽
 * 	作為@Bean方法上的注釋級別注解
 * 
 * 如果一個@Configuration類被標(biāo)記為@Conditional,則該類的所有@Bean方法、@Import注解和@ComponentScan注解都將受到條件約束。
 *
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 4.0
 * @see Condition
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * 必須匹配才能注冊組件的所有條件類
	 */
	Class<? extends Condition>[] value();

}

翻看上述源碼,可以看到 @Conditional 條件注解是從 Spring 4.0 開始引入的,它表示組件僅在所有指定條件匹配時才有資格注冊。比如,當(dāng)類加載器下存在某個指定的類的時候才會對注解的類進行實例化操作。

它唯一的元素屬性是接口 Condition 的數(shù)組,只有數(shù)組中指定的所有 Conditionmatches 方法都返回 true 的情況下,被注解的類才會被加載。我們前面講到的 OnClassCondition 等類就是 Condition 的子類之一。

/**
 * 一個必須匹配才能注冊的單個 Condition。
 *
 * <p> 在 bean 定義即將被注冊之前立即進行檢查,并可以根據(jù)在該點可以確定的任何標(biāo)準(zhǔn)自由否決注冊。
 *
 * <p> 條件必須遵循與 BeanFactoryPostProcessor 相同的限制,并確保不要與 bean 實例進行交互。
 * 對于與 @Configuration beans交互的更細(xì)粒度的控制,請考慮實現(xiàn) ConfigurationCondition 接口。
 *
 * @author Phillip Webb
 * @since 4.0
 * @see ConfigurationCondition
 * @see Conditional
 * @see ConditionContext
 */
@FunctionalInterface
public interface Condition {

	/**
	 * 確定條件是否匹配。
	 * @param context 條件上下文
	 * @param metadata 正在檢查的 AnnotationMetadata 或 MethodMetadata 的元數(shù)據(jù)
	 * @return 如果條件匹配并且可以注冊組件,則返回 true;否則返回 false,否決帶有注解的組件的注冊。
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

上述就是 Condition 接口的源碼,它的 matches 方法用來確定條件是否匹配,其中兩個參數(shù)分別如下:

  • ConditionContext :條件上下文,可通過該接口提供的方法來獲得 Spring 應(yīng)用的上下文信息,接口定義如下:

    public interface ConditionContext {
    
    	/**
    	 * 返回一個 BeanDefinitionRegistry 對象,該對象將包含如果條件匹配時應(yīng)該持有的bean定義。
    	 * 如果沒有可用的注冊表(這種情況很少見:只有當(dāng)使用 ClassPathScanningCandidateComponentProvider 時才會出現(xiàn)),
    	 * 則會拋出IllegalStateException異常。
    	 */
    	BeanDefinitionRegistry getRegistry();
    
    	/**
    	 * 返回一個 ConfigurableListableBeanFactory 對象,該對象將包含如果條件匹配時應(yīng)該持有的bean定義,
    	 * 或者 如果bean工廠不可用(或者無法向下轉(zhuǎn)型為 ConfigurableListableBeanFactory),則返回null。
    	 */
    	@Nullable
    	ConfigurableListableBeanFactory getBeanFactory();
    
    	/**
    	 * 返回當(dāng)前應(yīng)用程序正在運行的環(huán)境。
    	 */
    	Environment getEnvironment();
    
    	/**
    	 * 返回當(dāng)前正在使用的資源加載器。
    	 */
    	ResourceLoader getResourceLoader();
    
    	/**
    	 * 返回應(yīng)該用來加載額外類的 ClassLoader。如果系統(tǒng)類加載器不可訪問,則返回null。
    	 */
    	@Nullable
    	ClassLoader getClassLoader();
    
    }
    
  • AnnotatedTypeMetadata :該接口提供了訪問特定類或方法的注解功能,并且不需要加載類,可以用來檢查帶有 @Bean 注解的方法上是否還有其他注解。

    下面我們來查看下它的源碼【spring-core 5.3.25】:

    public interface AnnotatedTypeMetadata {
    	// 返回一個MergedAnnotations對象,表示該類型的注解集合。
        MergedAnnotations getAnnotations();
    	// 檢查是否存在指定名稱的注解,如果存在則返回true,否則返回false。
        default boolean isAnnotated(String annotationName) {
            return this.getAnnotations().isPresent(annotationName);
        }
    
    	// 下面的方法,都是用來獲取指定名稱注解的屬性值
        @Nullable
        default Map<String, Object> getAnnotationAttributes(String annotationName) {
            return this.getAnnotationAttributes(annotationName, false);
        }
    
        @Nullable
        default Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
            MergedAnnotation<Annotation> annotation = this.getAnnotations().get(annotationName, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared());
            return !annotation.isPresent() ? null : annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
        }
    
        @Nullable
        default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
            return this.getAllAnnotationAttributes(annotationName, false);
        }
    
        @Nullable
        default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
            Adapt[] adaptations = Adapt.values(classValuesAsString, true);
            return (MultiValueMap)this.getAnnotations().stream(annotationName).filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)).map(MergedAnnotation::withNonMergedAttributes).collect(MergedAnnotationCollectors.toMultiValueMap((map) -> {
                return map.isEmpty() ? null : map;
            }, adaptations));
        }
    }
    

2. @Conditional 的衍生注解

Spring Bootautoconfigure 項目中提供了各類基于@Conditional 注解的衍生注解,它們均位于 spring-boot-autoconfigure 項目的 org.springframework.boot.autoconfigure.condition 包下,如下圖所示:

【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解,開發(fā)框架-Spring Boot,spring boot,條件注解,Conditional,衍生注解

上述有好幾個條件注解,我們已經(jīng)接觸過了,下面我們再仔細(xì)介紹一下:

  • @ConditionalOnBean:當(dāng)容器中有指定 Bean 的條件下。

  • @ConditionalOnClass:當(dāng) classpath 類路徑下有指定類的條件下。

  • @ConditionalOnCloudPlatform:當(dāng)指定的云平臺處于 active 狀態(tài)時。

  • @ConditionalOnExpression:基于 SpEL 表達(dá)式的條件判斷。

  • @ConditionalOnJava:基于 JVM 版本作為判斷條件。

  • @ConditionalOnJndi:在 JNDI 存在的條件下查找指定的位置。

  • @ConditionalOnMissingBean:當(dāng)容器里沒有指定 Bean 的條件。

  • @ConditionalOnMissingClass:當(dāng)類路徑下沒有指定類的條件下。

  • @ConditionalOnNotWebApplication:當(dāng)項目不是一個 Web 項目的條件下。

  • @ConditionalOnProperty:當(dāng)指定的屬性有指定的值的條件下。

  • @ConditionalOnResource:類路徑是否有指定的值。

  • @ConditionalOnSingleCandidate:當(dāng)指定的 Bean 在容器中只有一個,或者有多個但是指定了首選的 Bean。

  • @ConditionalOnWarDeployment :當(dāng)應(yīng)用以 War 包形式部署時(例如在 Tomcat、Jetty 等 Web 服務(wù)器中)

  • @ConditionalOnWebApplication:當(dāng)項目是一個 Web 項目的條件下

如果我們仔細(xì)觀察這些注解的源碼,很快會發(fā)現(xiàn)它們其實都組合了@Conditional 注解,不同的是它們在注解中指定的條件(Condition)不同。

下面我們以前面博文中了解過的 @ConditionalOnWebApplication 為例,來對衍生條件注解進行一個簡單的分析:

/**
 * 用于條件性地匹配應(yīng)用程序是否為Web應(yīng)用程序。默認(rèn)情況下,任何Web應(yīng)用程序都會匹配,但可以通過type()屬性進行縮小范圍。
 *
 * @author Dave Syer
 * @author Stephane Nicoll
 * @since 1.0.0
 */
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnWebApplication {
	// 所需的web應(yīng)用類型
	Type type() default Type.ANY;
	// 可選應(yīng)用類型枚舉
	enum Type {	
		// 任何類型
      	ANY,
      	// 基于servlet的web應(yīng)用
      	SERVLET,
      	// 基于reactive的web應(yīng)用
      	REACTIVE
	}
}

通過查看 @ConditionalOnWebApplication 注解的源碼,我們發(fā)現(xiàn)它的確組合了 @Conditional 注解,并且指定了對應(yīng)的 ConditionOnWebApplicationCondition。該類繼承自 SpringBootCondition 并實現(xiàn) AutoConfigurationImportFilter 接口。

有關(guān) OnWebApplicationCondition 類的詳細(xì)介紹,請查看筆者的《【Spring Boot 源碼學(xué)習(xí)】OnWebApplicationCondition 詳解》,

了解了條件類的相關(guān)內(nèi)容后,我們可以用如下圖來表示 Condition 接口相關(guān)功能及實現(xiàn)類:

【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解,開發(fā)框架-Spring Boot,spring boot,條件注解,Conditional,衍生注解

總結(jié)

本篇我們介紹 @Conditional 條件注解及其衍生注解,至此有關(guān)自動配置裝配的流程已經(jīng)基本介紹完畢。

雖然我們從源碼角度對自動裝配流程有了清晰的認(rèn)識,但還是不能熟練地運用。那么下篇博文,我們將以 Spring Boot 內(nèi)置的 http 編碼功能為例來分析一下整個自動配置的過程。文章來源地址http://www.zghlxwxcb.cn/news/detail-734421.html

到了這里,關(guān)于【Spring Boot 源碼學(xué)習(xí)】@Conditional 條件注解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包