中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring 創建Bean 時是怎么判斷條件的

發布時間:2021-07-20 19:10:51 來源:億速云 閱讀:158 作者:chen 欄目:開發技術

本篇內容主要講解“Spring 創建Bean 時是怎么判斷條件的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring 創建Bean 時是怎么判斷條件的”吧!

我們在 Spring/ Spring Boot Starter  或者一些框架的源碼里經常能看到類似如下的注解聲明,可能作用在類上,也可能在某個方法上:

@ConditionalOnProperty(name = "spring.cloud.refresh.enabled", matchIfMissing = true)  @ConditionalOnProperty(prefix = "management.metrics.export.atlas", name = "enabled", havingValue = "true",     matchIfMissing = true)

我們一眼都能看出來,這是來「談條件」的。需要滿足某個屬性存在,或者屬性值是xx這一類的。

對于屬性的匹配,是會在 Environment 里查找是否包含當前需要的屬性,如果沒指定 havingValue  的話,那需要同時屬性的值不為「false」這個字符串,其它的東西都視為true。

今天的這篇做為鋪墊,先來描述一下注解的工作原理,后面一篇我會寫寫與此有關的一個有趣的案例。

工作原理

濃縮版

在SpringBoot 啟動過程中,會掃描當前依賴里的  @Configuration,然后遍歷的過程中會判斷其中哪些是要講條件的。對于講條件的這些,會判斷

shouldSkip ,這里的是否跳過,會根據注解作用在類上,方法上,轉向不同的Metadata,提取對應的實現類,但本質上還是通過 resolver  去Environment 里找找這個屬性在不在,不在跳過,在的話是否值匹配。從而決定 Confirutaion 是否生效。

源碼版

我們知道 Spring 啟動的過程,也是創建和初始化Bean 的過程,在這個過程中,會先拿到BeanNames,并一個個的去創建和初始化。

此時,對于Configuration,是通過BeanPostProcessor的方式來處理的.

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {     int registryId = System.identityHashCode(registry);     this.registriesPostProcessed.add(registryId);     processConfigBeanDefinitions(registry);// 對,是這里   }

部分調用棧如下:

java.lang.Thread.State: RUNNABLE     at org.springframework.boot.autoconfigure.condition.OnPropertyCondition.getMatchOutcome(OnPropertyCondition.java:65)     at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)     at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:181)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:142)     at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:118)     at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:328)     at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:233)

這里對于 Class 和 Method,都在該方法中,處理入口不一樣,傳入的Meta也有所區別

/**    * Build and validate a configuration model based on the registry of    * {@link Configuration} classes.    */   public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {     List<BeanDefinitionHolder> configCandidates = new ArrayList<>();     String[] candidateNames = registry.getBeanDefinitionNames();      for (String beanName : candidateNames) {       BeanDefinition beanDef = registry.getBeanDefinition(beanName);       if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||           ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {       }       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));       }     }     // Return immediately if no @Configuration classes were found     if (configCandidates.isEmpty()) {       return;     }      // Parse each @Configuration class     ConfigurationClassParser parser = new ConfigurationClassParser(         this.metadataReaderFactory, this.problemReporter, this.environment,         this.resourceLoader, this.componentScanBeanNameGenerator, registry);      Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);     Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());     do {       parser.parse(candidates); // 這里處理class       parser.validate();        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());       configClasses.removeAll(alreadyParsed);        // Read the model and create bean definitions based on its content       if (this.reader == null) {         this.reader = new ConfigurationClassBeanDefinitionReader(             registry, this.sourceExtractor, this.resourceLoader, this.environment,             this.importBeanNameGenerator, parser.getImportRegistry());       }       this.reader.loadBeanDefinitions(configClasses); // 這里處理Method       alreadyParsed.addAll(configClasses);     while (!candidates.isEmpty());   }

里面的邏輯,則都是在判斷這些Condition 是否match,重點看這一行

condition.matches(this.context, metadata)

for (Condition condition : conditions) {       ConfigurationPhase requiredPhase = null;       if (condition instanceof ConfigurationCondition) {         requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();       }       if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {         return true;       }     }

Spring 創建Bean 時是怎么判斷條件的

通過觀察 Condition 這個接口你也能發現,和我們上面說的一樣,這里不同的處理metadata是不同的。

在 SpringBoot 里,ConditionalOnProperty 的 Condition 實現,運用了一個模板方法模式,  SpringBootCondition 做為模板,再調用各子類的實現方法。

public final boolean matches(ConditionContext context,       AnnotatedTypeMetadata metadata) {     String classOrMethodName = getClassOrMethodName(metadata);       ConditionOutcome outcome = getMatchOutcome(context, metadata);// 這里交給了抽象方法       recordEvaluation(context, classOrMethodName, outcome);       return outcome.isMatch();   }

來看子類的實現

private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes,       PropertyResolver resolver) {     Spec spec = new Spec(annotationAttributes);     List<String> missingProperties = new ArrayList<>();     List<String> nonMatchingProperties = new ArrayList<>();     spec.collectProperties(resolver, missingProperties, nonMatchingProperties);     if (!missingProperties.isEmpty()) {       return ConditionOutcome.noMatch(           ConditionMessage.forCondition(ConditionalOnProperty.class, spec)               .didNotFind("property", "properties")               .items(Style.QUOTE, missingProperties));     }     if (!nonMatchingProperties.isEmpty()) {       return ConditionOutcome.noMatch(           ConditionMessage.forCondition(ConditionalOnProperty.class, spec)               .found("different value in property",                   "different value in properties")               .items(Style.QUOTE, nonMatchingProperties));     }     return ConditionOutcome.match(ConditionMessage         .forCondition(ConditionalOnProperty.class, spec).because("matched"));   }

有了這個判斷,對于 OnClass 之類的,你也能猜個八九不離十。

同樣會有一個子類的實現

Spring 創建Bean 時是怎么判斷條件的

只不過判斷的從屬性,換成了在classloader里查找已加載的類。

Spring 創建Bean 時是怎么判斷條件的

到此,相信大家對“Spring 創建Bean 時是怎么判斷條件的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武隆县| 紫阳县| 海盐县| 仙桃市| 资中县| 开江县| 镇赉县| 大冶市| 乌苏市| 唐河县| 宜宾市| 张家港市| 梁平县| 福海县| 手机| 肥西县| 莱阳市| 巩义市| 来安县| 武夷山市| 宣恩县| 栖霞市| 西丰县| 濮阳市| 淮北市| 环江| 定日县| 习水县| 蒙阴县| 阳曲县| 疏勒县| 美姑县| 夏邑县| 昌吉市| 福建省| 东乡族自治县| 龙门县| 奈曼旗| 镇安县| 襄汾县| 诸城市|