1. 程式人生 > >SOFABoot原始碼解析之啟動原理(2)-原始碼解析

SOFABoot原始碼解析之啟動原理(2)-原始碼解析

1.  private voidprocessImports(ConfigurationClass configClass, SourceClass currentSourceClass,
2.           Collection<SourceClass>importCandidates, boolean checkForCircularImports) throws IOException {
3.  4.         ……
5.       if(checkForCircularImports && isChainedImportOnStack(configClass)) {
6.           ……
7.       }
8.       else{
9.           this.importStack.push(configClass);
10.          try{
11. for (SourceClass candidate : importCandidates){
12. if(candidate.isAssignable(ImportSelector.class)) {
13.                      //Candidate class is an ImportSelector -> delegate to it to determine imports
14.                      Class<?>candidateClass = candidate.loadClass();
15.                      ImportSelectorselector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
16.                      ParserStrategyUtils.invokeAwareMethods(
17.                              selector,this.environment, this.resourceLoader, this.registry);
18.                      if(this.deferredImportSelectors != null && selector instanceofDeferredImportSelector) {
19. this.deferredImportSelectors.add(
20.                                  newDeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
21.                      }
22.                      else{
23.                          String[]importClassNames = selector.selectImports(currentSourceClass.getMetadata());
24.                          Collection<SourceClass>importSourceClasses = asSourceClasses(importClassNames);
25. processImports(configClass,currentSourceClass, importSourceClasses, false);
26.                      }
27.                  }
28.                  elseif (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
29.                      //Candidate class is an ImportBeanDefinitionRegistrar ->
30.                      //delegate to it to register additional bean definitions
31.                      Class<?>candidateClass = candidate.loadClass();
32.                      ImportBeanDefinitionRegistrarregistrar =
33.                              BeanUtils.instantiateClass(candidateClass,ImportBeanDefinitionRegistrar.class);
34.                      ParserStrategyUtils.invokeAwareMethods(
35.                              registrar,this.environment, this.resourceLoader, this.registry);
36. configClass.addImportBeanDefinitionRegistrar(registrar,currentSourceClass.getMetadata());
37.                  }
38.                  else{
39.                      //Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
40.                      //process it as an @Configuration class
41.                      this.importStack.registerImport(
42.                              currentSourceClass.getMetadata(),candidate.getMetadata().getClassName());
43. processConfigurationClass(candidate.asConfigClass(configClass));
44.                  }
45.              }
46.          }
47.          catch(BeanDefinitionStoreException ex) {
48.              throwex;
49.          }
50.          catch(Throwable ex) {
51.              ……
52.          }
53.          finally{
54.              this.importStack.pop();
55.          }
56.      }
57. }

        processImports方法主要邏輯:

        1)   如果匯入的配置類實現了DeferredImportSelector介面,則建立DeferredImportSelectorHolder例項,並置入deferredImportSelectors連結串列中,待上述processConfigBeanDefinitions方法下一個do{*}while(*)迴圈中處理。

        2)   如果匯入的配置類實現了ImportSelector介面,則呼叫該類的selectImports方法匯入新的@Configuration配置類,並巢狀呼叫processImports方法,處理匯入的@Configuration配置類。

        3)   如果匯入的配置類實現了ImportBeanDefinitionRegistrar介面,則建立ImportBeanDefinitionRegistrar例項,並在處理@Configuration配置類過程中,委託該例項註冊額外的BeanDefinition。

        4)   如果以上都不是,則匯入的配置類為基本的@Configuration配置類,直接呼叫processConfigurationClass處理,最終具體解析操作在doProcessConfigurationClass方法中實現。

1.  protected final SourceClassdoProcessConfigurationClass(ConfigurationClass configClass, SourceClasssourceClass) throws IOException {
2.       //Recursively process any member (nested) classes first
3.       processMemberClasses(configClass,sourceClass);
4.  5.  //處理@PropertySource註解
6.       for(AnnotationAttributes propertySource :AnnotationConfigUtils.attributesForRepeatable(
7.               sourceClass.getMetadata(),PropertySources.class, org.springframework.context.annotation.PropertySource.class)){
8.           if(this.environment instanceof ConfigurableEnvironment) {
9.               processPropertySource(propertySource);
10.          }
11.          else{
12.              logger.warn("[email protected] annotation on [" + sourceClass.getMetadata().getClassName()+
13.                      "].Reason: Environment must implement ConfigurableEnvironment");
14.          }
15.      }
16. 17. // 處理@ComponentScan註解
18.      Set<AnnotationAttributes>componentScans = AnnotationConfigUtils.attributesForRepeatable(
19.              sourceClass.getMetadata(),ComponentScans.class, ComponentScan.class);
20.      if(!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)) {
21.          for(AnnotationAttributes componentScan : componentScans) {
22.              //The config class is annotated with @ComponentScan -> perform the scanimmediately
23.              Set<BeanDefinitionHolder>scannedBeanDefinitions =
24. this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName());
25.              //Check the set of scanned definitions for any further config classes and parserecursively if necessary
26.              for(BeanDefinitionHolder holder : scannedBeanDefinitions) {
27.                  if(ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(),this.metadataReaderFactory)) {
28.                      parse(holder.getBeanDefinition().getBeanClassName(),holder.getBeanName());
29.                  }
30.              }
31.          }
32.      }
33. 34. //處理@Import註解
35. processImports(configClass, sourceClass,getImports(sourceClass), true);
36. 37. //處理@ImportResource註解
38.      if(sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
39.          AnnotationAttributesimportResource =
40.                  AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),ImportResource.class);
41.          String[]resources = importResource.getStringArray("locations");
42.          Class<?extends BeanDefinitionReader> readerClass =importResource.getClass("reader");
43.          for(String resource : resources) {
44.              StringresolvedResource = this.environment.resolveRequiredPlaceholders(resource);
45.              configClass.addImportedResource(resolvedResource,readerClass);
46.          }
47.      }
48. 49. //處理@Bean方法
50.      Set<MethodMetadata>beanMethods =sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
51.      for(MethodMetadata methodMetadata : beanMethods) {
52.          configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));
53.      }
54. 55.      ……
56. 57.      //No superclass -> processing is complete
58.      returnnull;
59. }

        針對每個@Configuration配置類,依次處理@Configuration配置類中的@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean註解,主要解析過程如下:

        1)   @PropertySource處理過程:呼叫processPropertySource方法處理屬性源,在此不詳述;

        2)   @ComponentScan處理過程:解析@Configuration配置類中@ComponentScan、@ComponentScans註解,並根據設定的basePackages掃描指定的包路徑,並載入、註冊所有帶有@Component註解及@Component衍生註解(如@Controller、@Service、@Repository、@Configuration等)Java類的Bean定義到Spring應用上下文;

        3)   @Import處理過程:參考上述processImports方法描述。需要注意,在處理某個配置類的@Import註解過程中,如果發現@Import匯入的類實現了DeferredImportSelector介面,則建立DeferredImportSelectorHolder例項,並置入deferredImportSelectors連結串列中,待下一次迴圈處理。以此類推,直至所有的@Configuration配置類載入完畢。例如:在處理SofaBootRpcDemoApplication的@Import註解時,由於在SofaBootRpcDemoApplication類@SpringBootApplication註解中引用了@EnableAutoConfiguration註解,而它又引用了@Import(value={EnableAutoConfigurationImportSelector.class})。由於EnableAutoConfigurationImportSelector實現了DeferredImportSelector介面,所以在此建立DeferredImportSelectorHolder例項,並置入deferredImportSelectors連結串列中,待所有@Configuration註解類解析完成以後再處理。

        4)   @ImportResource處理過程:解析locations屬性,並依次獲取locations指定目錄下Spring XML配置檔案,設定configClass類的importedResource屬性;

        5)   @Bean處理過程:讀取@Configuration配置類中@Bean註解的方法,並增加到configClass的beanMethod集合。

        至此,處理完現有candidates中所有@Configuration配置類。

        在回看一下processConfigBeanDefinitions方法:

相關推薦

SOFABoot原始碼解析啟動原理2-原始碼解析

1.  private voidprocessImports(ConfigurationClass configClass, SourceClass currentSourceClass,2.           Collection<SourceClass>importCandidates, b

SOFABoot原始碼解析啟動原理1-註解分析

一 、概述        SOFABoot是螞蟻金服開源的基於 Spring Boot 的研發框架,它在Spring Boot 的基礎上,提供了諸如 Readiness Check,類隔離,日誌空間隔離等等能力。在增強了 Spring Boot 的同時,SOFABoot 提供

elasticsearch原始碼分析啟動過程

最近開始廣泛的使用elasticsearch,也開始寫一些java程式碼了,為了提高java程式碼能力,也為了更加深入一點了解elasticsearch的內部運作機制,所以開始看一些elasticsearch的原始碼了。對於這種廣受追捧的開源專案,細細品讀一定會受益匪淺,

併發程式設計十二—— Java 執行緒池 實現原理原始碼深度解析 submit方法

在上一篇《併發程式設計(十一)—— Java 執行緒池 實現原理與原始碼深度解析(一)》中提到了執行緒池ThreadPoolExecutor的原理以及它的execute方法。這篇文章是接著上一篇文章寫的,如果你沒有閱讀上一篇文章,建議你去讀讀。本文解析ThreadPoolExecutor#submit。  

Android View原理解析測量流程measure

提示:本文的原始碼均取自Android 7.0(API 24) 前言 自定義View是Android進階路線上必須攻克的難題,而在這之前就應該先對View的工作原理有一個系統的理解。本系列將分為4篇部落格進行講解,本文主要對View的測量流程進行講解。相關內容如

Android View原理解析佈局流程layout

提示:本文的原始碼均取自Android 7.0(API 24) 前言 自定義View是Android進階路線上必須攻克的難題,而在這之前就應該先對View的工作原理有一個系統的理解。本系列將分為4篇部落格進行講解,本文主要對View的佈局流程進行講解。相關內容如

mybatis原始碼解析Configuration載入

概要 上一篇,我們主要搭建了一個簡單的環境,這邊我們主要來分析下mybatis是如何來載入它的配置檔案Configuration.xml的。 分析 1 public class App { 2 public static void main(String[] args) { 3

mybatis原始碼解析Configuration載入

概述 上一篇我們講了configuation.xml中幾個標籤的解析,例如<properties>,<typeAlises>,<settings>等,今天我們來介紹剩下的兩個比較重要的標籤之一,<environments>,這個標籤主要用於我們訪問資料庫的配置

LDA原理2知識儲備貝葉斯派和概率派

介紹貝葉斯派和概率派 概率派認為要推斷的引數是固定的值,雖然概率是未知的,但是一定是固定的值,同時樣本是隨機的,既然這樣,他們的側重點就是研究樣本空間,比如我們不知道拋硬幣正面朝上的概率,那概率派的思路就是做很多次的拋硬幣的實驗,試驗次數越多,越能逼近概率

Android4.4.2原始碼分析WiFi模組

已經寫了幾篇關於Android原始碼的,原始碼程式碼量太大,所以如果想分析某個模組可能不知如何下手,說一下思路 1,分析原始碼英文閱讀能力要夠,想要分析某個模組一般找模組對應的英文,就是模組 2,找到之後首先檢視清單配置檔案Androidmani.fest,找到程式主介面activity 3,通過檢視配置檔

Codis原始碼解析——處理slot操作2

這一篇我們把處理slot操作的機制講完。還剩最後兩個部分。一個是fillSlot,一個是每一個槽具體的處理方式。 本例中有兩個group,將之前auto-rebalance過的slot(0-511屬於group1,512-1023屬於group2) 現在

Android4.4.2原始碼分析WiFi模組

接著上一篇繼續對WiFi原始碼的分析 onResume方法中 6>,首先是呼叫WiFiEnabler的resume方法對switch進行管理 接下來註冊廣播 getActivity().registerReceiver(mReceiver, mFilter);

ConcurrentHashMap原理2用分離鎖實現多個執行緒間的併發寫操作

ConcurrentHashMap 類 ConcurrentHashMap 在預設併發級別會建立包含 16 個 Segment 物件的陣列。每個 Segment 的成員物件 table 包含若干個散列表的桶。每個桶是由 HashEntry 連結起來的一個連結串列。如果鍵能均

spring原始碼解析IOC容器

  學習優秀框架的原始碼,是提升個人技術水平必不可少的一個環節。如果只是停留在知道怎麼用,但是不懂其中的來龍去脈,在技術的道路上註定走不長遠。最近,學習了一段時間的spring原始碼,現在整理出來,以便日後溫故知新。   IOC容器是spring最核心的模組之一,是整個spring體系的基石,spring其

spring原始碼解析IOC容器------載入和註冊

  上一篇跟蹤了IOC容器對配置檔案的定位,現在我們繼續跟蹤程式碼,看看IOC容器是怎麼載入和註冊配置檔案中的資訊的。開始之前,首先我們先來了解一下IOC容器所使用的資料結構-------BeanDefinition,它是一個上層介面,有很多實現類,分別對應不同的資料載體。我們平時開發的時候,也會定義很多po

spring原始碼解析IOC容器——依賴注入

  上一篇主要是跟蹤了IOC容器對bean標籤進行解析之後存入Map中的過程,這些bean只是以BeanDefinition為載體單純的儲存起來了,並沒有轉換成一個個的物件,今天繼續進行跟蹤,看一看IOC容器是怎樣例項化物件的。   我們都使用過以下程式碼: 1 FileSystemXmlApplicati

Spring原始碼解析基礎應用

方法注入 在spring容器中,大部分bean的作用域(scope)是單例(singleton)的,少部分bean的作用域是原型(prototype),如果一個bean的作用域是原型,我們A bean的作用域是原型,B bean中以@Autowired的方式注入A,那麼B在A中依舊是單例。我們可以讓B類實現A

Spring原始碼解析基礎應用

組合Java配置 在XML中,我們可以使用<import/>標籤,在一個XML檔案中引入另一個XML檔案,在Java類中,我們同樣可以在一個配置類中用@Import引入另一個配置類,被引入的配置類中的@Bean也會載入到spring容器。程式碼如下: @Configuration public

斷點 相關技術與原理2

def pan 保存 ollydbg php class 工具 code http 繼續對OD的斷點技術做個筆記。 1、硬件斷點: Intel CPU中有8個調試寄存器(Debug Register)DR0 — DR7,當中DR0 — DR3用於設置硬件斷點地址,D

HectorSLAM論文解析?代碼重寫2

開始 機器人 狀態 核心 基本上 測試數據 logs grid 機器 這篇文章為HectorSLAM系列的以下部分 HectorSLAM的整體邏輯 激光匹配 地圖構造 地圖更新 500行代碼重寫一個LidarSLAM 測試數據的準備,和測試數據讀取模塊的編寫