最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中的@Conditional注解實現(xiàn)分析

 更新時間:2023年12月29日 09:21:14   作者:it_lihongmin  
這篇文章主要介紹了Spring中的@Conditional注解實現(xiàn)分析,  @Conditional是Spring 4出現(xiàn)的注解,但是真正露出價值的是Spring Boot的擴展@ConditionalOnBean等,需要的朋友可以參考下

@Conditional注解實現(xiàn)分析

@Conditional是Spring 4出現(xiàn)的注解,但是真正露出價值的是Spring Boot的擴展@ConditionalOnBean等。但是任然使用的是Spring框架進行處理,并沒有做太多定制的東西,所以還是先看看@Conditional注解的實現(xiàn)。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
 
	/**
	 * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();
 
}

先看看@Conditional注解的結構比較簡單,只需要定義一個Condition子類即可,并且說明只有滿足了當前Condition的matches方法時才會將當前@Component注冊成Bean。那么再看看Condition接口和體系。

/**
 * @since 4.0
 * @see ConfigurationCondition
 * @see Conditional
 * @see ConditionContext
 */
@FunctionalInterface
public interface Condition {
 
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

當前會傳入ConditionContext和AnnotatedTypeMetadata進行回調,返回是否匹配,如果不匹配則不會注冊成Bean。但是這是在哪里進行回調的呢?

ConfigurationClassParser # processConfigurationClass (ConfigurationClassParser # doProcessConfigurationClass等)

ConditionEvaluator # shouldSkip

比較清楚了,又是在處理@Import、@ComponentScan、ImportSelector等的處理類ConfigurationClassParser執(zhí)行時機比較清楚了

再看看Condition的結構體系:

大致有四類

1)、ProfileCondition,項目啟動后Profile信息存放在ApplicationContext的Environment中,能拿到兩者之一就可以判斷。

2)、ConfigurationCondition

public interface ConfigurationCondition extends Condition {
 
    // 定義了子類必須實現(xiàn),返回下面枚舉的一種
    ConfigurationPhase getConfigurationPhase();
 
    // 判斷階段
	enum ConfigurationPhase {
            
        // Conponent階段,即將@Component加入到BeanFactory
        PARSE_CONFIGURATION,
 
        // 只有通過getBean才能正在將Bean注冊到Ioc容器中。前提是要將BeanDefinition添加到 
        // BeanFactory中
        REGISTER_BEAN
    }
}

3)、ConditionEvalutionReport,Spring Boot報表相關

4)、SpringBootCondition,直接是Spring Boot中擴展的。下一篇博客,具體分析 @ConditionalOnBean等再具體分析。

幾個的角色比較清楚了,只要一個@Conditional注解,注解的屬性為@Condition或其子類。根據回調@Condition的matches方法,即可判斷是否將注冊成Bean。

先看看回調時機,都是在處理@Component、@ComponentSacn、ImportSelector等情況注冊Bean時。

由于情況比較復雜,可能@Component上有@ComponentScan,則會遞歸進行處理,總之都會先調用ConfigurationClassParser的ConditionEvaluator conditionEvaluator的shouldSkip方法判斷是否跳過。

比如:

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),  
           ConfigurationPhase.PARSE_CONFIGURATION)) {
 
        return;
    }
 
    // 省略其余代碼
}

而conditionEvaluator在ConfigurationClassParser的構造器中被初始化,如下:

this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);

先看看ConditionEvaluator的類結構

class ConditionEvaluator {
 
    private final ConditionContextImpl context;
 
    public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
			@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
 
		this.context = new ConditionContextImpl(registry, environment, resourceLoader);
	}
    
    // 省略其他方法
 
    private static class ConditionContextImpl implements ConditionContext {
 
        private final BeanDefinitionRegistry registry;
 
        private final ConfigurableListableBeanFactory beanFactory;
 
        private final Environment environment;
 
        private final ResourceLoader resourceLoader;
 
        private final ClassLoader classLoader;
 
        public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
                                    @Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
 
            this.registry = registry;
            this.beanFactory = deduceBeanFactory(registry);
            this.environment = (environment != null ? environment : deduceEnvironment(registry));
            this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
            this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
        }
    }
}

也就是說,在ConfigurationClassParser構造器中初始化ConditionEvaluator時候,就初始化了內部類ConditionContextImpl,并且傳入了BeanFactory(Bean是否存在可以通過工廠進行判斷)、Environment(環(huán)境配置、Profile等存放在其中)、ResourceLoader(Spring的Resource加載器)、ClassLoader(類加載器)等。

到這里就比較清楚了,回調Condition的matches接口時傳入這些組件的類ConditionContextImpl,要實現(xiàn)@ConditionalOnBean、@OnPropertyCondition、@Profile、@ConditionalOnClass等都比較簡單了。

在調用Condition的matches時,不僅傳入了ConditionContextImpl,還出入了AnnotatedTypeMetadata,這是當前注解結合被Spring封裝的注解元信息。理解比較抽象,比如自動裝配EmbeddedTomcat時需要同時存在Servlet、Tomcat、upgradeProtocol類;并且沒有將ServletWebServerFactory注冊成Bean,此時Component才能真正生效,如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
    // 省略其他代碼
}

具體再看看ConditionEvaluator的shouldSkip方法的實現(xiàn):

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    // 注解信息不能為空, 并且必須有Conditional或者其子類
    if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
        return false;
    }
    // 如果判斷階段為空,進行類型判斷再遞歸調用該方法
    if (phase == null) {
        if (metadata instanceof AnnotationMetadata &&
                ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
            return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
        }
        return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    }
 
    List<Condition> conditions = new ArrayList<>();
    // 獲取多有的Condition類型,如上面的EmbeddedTomcat同時需要多個條件成立
    for (String[] conditionClasses : getConditionClasses(metadata)) {
        for (String conditionClass : conditionClasses) {
            Condition condition = getCondition(conditionClass, this.context.getClassLoader());
            conditions.add(condition);
        }
    }
    // 條件排序(根據Spring的那三個排序方式定義)
    AnnotationAwareOrderComparator.sort(conditions);
 
    for (Condition condition : conditions) {
        ConfigurationPhase requiredPhase = null;
        if (condition instanceof ConfigurationCondition) {
            requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
        }
        // 判斷階段為空(非ConfigurationCondition的子類)、不需要判斷階段,則直接返回true
        // 否則才調用matches接口判斷
        if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
            return true;
        }
    }
    return false;
}

1)、注解信息不能為空, 并且必須有Conditional或者其子類

2)、階段為null,則根據情況設置階段后再遞歸調用該方法

3)、獲取所有的Condition列表

4)、進行排序

5)、遍歷Condition,是否在該階段進行判斷。需要則再調用該Condition的matches方法

總結:添加了@Conditional或者@ConditionXXX注解,其value值會對應一個Condition或者子類的Class。在處理@ComponentScan、ImportSelector等時會根據判斷階段,調用Condition的matches方法判斷是否進行注冊成Bean。從而實現(xiàn)各種復雜的動態(tài)判斷注冊成Bean的情況。

到此這篇關于Spring中的@Conditional注解實現(xiàn)分析的文章就介紹到這了,更多相關@Conditional注解實現(xiàn)分析內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Spring Boot 4 與 Spring Framework 7新特性、升級要點與實戰(zhàn)指南

    Spring Boot 4 與 Spring Framework&nb

    SpringBoot4和SpringFramework7帶來了大量新特性,包括升級到JakartaEE11、支持Java21、增強模塊化、優(yōu)化測試、增加彈性功能等,本文介紹Spring Boot 4 與 Spring Framework 7新特性、升級要點與實戰(zhàn)指南,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • java+mysql實現(xiàn)登錄和注冊功能

    java+mysql實現(xiàn)登錄和注冊功能

    這篇文章主要為大家詳細介紹了java+mysql實現(xiàn)登錄和注冊功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • java實現(xiàn)時鐘表盤

    java實現(xiàn)時鐘表盤

    這篇文章主要為大家詳細介紹了java實現(xiàn)時鐘表盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • springboot部署linux訪問服務器資源的方法

    springboot部署linux訪問服務器資源的方法

    這篇文章主要介紹了springboot部署linux訪問服務器資源,部署springboot項目至服務器用了幾種不同方法,文中給大家詳細介紹,需要的朋友可以參考下
    2019-12-12
  • Java實現(xiàn)時間戳轉代碼運行時長

    Java實現(xiàn)時間戳轉代碼運行時長

    這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)時間戳轉代碼運行時長功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-06-06
  • Java限流方法常見實現(xiàn)方案(單機限流和分布式限流)

    Java限流方法常見實現(xiàn)方案(單機限流和分布式限流)

    Java限流用于保護系統(tǒng)資源,分為單機(Guava/滑動窗口)和分布式(Redis+Lua)方案,核心算法包括固定窗口、令牌桶、漏桶等,推薦使用Sentinel等成熟框架實現(xiàn)動態(tài)流量控制,本文介紹Java限流方法常見實現(xiàn)方案(單機限流和分布式限流),感興趣的朋友一起看看吧
    2025-08-08
  • Java?Stream流以及常用方法操作實例

    Java?Stream流以及常用方法操作實例

    Stream是對Java中集合的一種增強方式,使用它可以將集合的處理過程變得更加簡潔、高效和易讀,這篇文章主要介紹了Java?Stream流以及常用方法的相關資料,需要的朋友可以參考下
    2025-08-08
  • SpringBoot文件上傳接口并發(fā)性能調優(yōu)

    SpringBoot文件上傳接口并發(fā)性能調優(yōu)

    在一個項目現(xiàn)場,文件上傳接口(文件500K)QPS只有30,這個并發(fā)性能確實堪憂,此文記錄出坑過程,文中通過代碼示例講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2024-06-06
  • Java Set 中的常用方法示例總結

    Java Set 中的常用方法示例總結

    Set是Java集合框架(Collection Framework)中最常用的接口之一,具有元素唯一、不允許重復 的特性,這篇文章將全面總結Java Set的常用方法并通過示例進行講解,主要用于日常查詢使用,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解

    Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解

    這篇文章主要介紹了Java Math.round(),Math.ceil(),Math.floor()的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08

最新評論

连平县| 隆回县| 陆河县| 文安县| 丹棱县| 清苑县| 曲阳县| 两当县| 温泉县| 思南县| 噶尔县| 沙雅县| 韶山市| 平阴县| 含山县| 上虞市| 砀山县| 板桥市| 同仁县| 大足县| 扶沟县| 三门县| 廊坊市| 巍山| 平乐县| 青岛市| 宽甸| 卢氏县| 古交市| 贵阳市| 牙克石市| 肃宁县| 衡阳市| 阿图什市| 昭苏县| 章丘市| 桑日县| 来安县| 天水市| 新蔡县| 岑巩县|