成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

[[380145]]

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

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

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

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

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

工作原理

濃縮版

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

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

源碼版

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

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

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

部分調用棧如下:

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

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

  1. /** 
  2.    * Build and validate a configuration model based on the registry of 
  3.    * {@link Configuration} classes. 
  4.    */ 
  5.   public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { 
  6.     List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); 
  7.     String[] candidateNames = registry.getBeanDefinitionNames(); 
  8.  
  9.     for (String beanName : candidateNames) { 
  10.       BeanDefinition beanDef = registry.getBeanDefinition(beanName); 
  11.       if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || 
  12.           ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { 
  13.       } 
  14.       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { 
  15.         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); 
  16.       } 
  17.     } 
  18.     // Return immediately if no @Configuration classes were found 
  19.     if (configCandidates.isEmpty()) { 
  20.       return
  21.     } 
  22.  
  23.     // Parse each @Configuration class 
  24.     ConfigurationClassParser parser = new ConfigurationClassParser( 
  25.         this.metadataReaderFactory, this.problemReporter, this.environment, 
  26.         this.resourceLoader, this.componentScanBeanNameGenerator, registry); 
  27.  
  28.     Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); 
  29.     Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); 
  30.     do { 
  31.       parser.parse(candidates); // 這里處理class 
  32.       parser.validate(); 
  33.  
  34.       Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); 
  35.       configClasses.removeAll(alreadyParsed); 
  36.  
  37.       // Read the model and create bean definitions based on its content 
  38.       if (this.reader == null) { 
  39.         this.reader = new ConfigurationClassBeanDefinitionReader( 
  40.             registry, this.sourceExtractor, this.resourceLoader, this.environment, 
  41.             this.importBeanNameGenerator, parser.getImportRegistry()); 
  42.       } 
  43.       this.reader.loadBeanDefinitions(configClasses); // 這里處理Method 
  44.       alreadyParsed.addAll(configClasses); 
  45.     while (!candidates.isEmpty()); 
  46.   } 

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

condition.matches(this.context, metadata)

  1. for (Condition condition : conditions) { 
  2.       ConfigurationPhase requiredPhase = null
  3.       if (condition instanceof ConfigurationCondition) { 
  4.         requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); 
  5.       } 
  6.       if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) { 
  7.         return true
  8.       } 
  9.     } 

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

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

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

來看子類的實現

  1. private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes, 
  2.       PropertyResolver resolver) { 
  3.     Spec spec = new Spec(annotationAttributes); 
  4.     List<String> missingProperties = new ArrayList<>(); 
  5.     List<String> nonMatchingProperties = new ArrayList<>(); 
  6.     spec.collectProperties(resolver, missingProperties, nonMatchingProperties); 
  7.     if (!missingProperties.isEmpty()) { 
  8.       return ConditionOutcome.noMatch( 
  9.           ConditionMessage.forCondition(ConditionalOnProperty.class, spec) 
  10.               .didNotFind("property""properties"
  11.               .items(Style.QUOTE, missingProperties)); 
  12.     } 
  13.     if (!nonMatchingProperties.isEmpty()) { 
  14.       return ConditionOutcome.noMatch( 
  15.           ConditionMessage.forCondition(ConditionalOnProperty.class, spec) 
  16.               .found("different value in property"
  17.                   "different value in properties"
  18.               .items(Style.QUOTE, nonMatchingProperties)); 
  19.     } 
  20.     return ConditionOutcome.match(ConditionMessage 
  21.         .forCondition(ConditionalOnProperty.class, spec).because("matched")); 
  22.   } 

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

同樣會有一個子類的實現

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

本文轉載自微信公眾號「Tomcat那些事兒」,可以通過以下二維碼關注。轉載本文請聯系Tomcat那些事兒公眾號。

 

責任編輯:武曉燕 來源: Tomcat那些事兒
相關推薦

2021-03-08 08:40:25

Spring Bean 創建單例對象

2021-05-11 07:42:59

BeanSpring屬性

2011-04-12 09:53:32

Spring

2023-10-07 08:35:07

依賴注入Spring

2024-12-31 11:40:05

2021-04-30 20:25:20

Spring MVCJava代碼

2024-02-23 10:33:34

SpringBean容器

2009-06-17 17:04:37

BeanFactorySpring

2023-09-28 08:15:05

SpringBean加載

2010-03-24 15:40:39

網管運維管理摩卡軟件

2020-10-27 07:34:41

基站手機蜂窩網絡

2025-06-13 02:10:00

MySQL大表業務場景

2011-03-18 09:27:00

Spring

2024-01-23 08:47:13

BeanSpring加載方式

2022-07-20 07:45:52

POJOJavaSpring IoC

2022-05-27 08:25:55

容器Spring

2025-04-25 11:25:00

SpringBean初始化

2015-09-06 09:09:13

2014-06-20 10:34:42

開源

2019-03-18 10:02:16

緩存更新數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品国产一区二区三区性色av | 99精品视频在线观看 | 国产日韩一区二区 | 久久精品久久久久久 | 欧美日韩福利 | 精品视频一区二区三区 | 国产精品美女久久久久久久久久久 | 成人精品鲁一区一区二区 | 天天看天天操 | 国产欧美一区二区三区在线看 | 国产精品一区二区视频 | 亚洲精品电影网在线观看 | 91成人在线 | 在线欧美a | 伊人狠狠干 | 国产精品我不卡 | 国产一级在线观看 | 免费看片在线播放 | 日本黄色激情视频 | 亚洲精品乱码久久久久久久久久 | 激情欧美一区二区三区 | 精品丝袜在线 | 精品1区2区| 国产成人精品久久 | 亚洲性视频网站 | 一区在线观看 | 噜噜噜色网 | 日韩1区| 成人免费视频一区 | 日本高清中文字幕 | 中文字幕在线三区 | 欧美日韩国产一区二区三区不卡 | 91精品国产麻豆 | www.99热| 欧美精品1区 | 久久噜噜噜精品国产亚洲综合 | 亚洲国产精品久久久久婷婷老年 | 欧美三级在线 | 伊人精品久久久久77777 | 日本亚洲一区二区 | 日韩中文视频 |