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

溫馨提示×

溫馨提示×

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

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

Spring BeanDefinition的加載過程

發布時間:2021-06-26 15:03:33 來源:億速云 閱讀:129 作者:chen 欄目:大數據

本篇內容主要講解“Spring BeanDefinition的加載過程”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Spring BeanDefinition的加載過程”吧!

一.XML定義

?XML配置的加載由AbstractXmlApplicationContext實現,方法實現如下:

Spring BeanDefinition的加載過程

Spring BeanDefinition的加載過程

?主要是實例化了一個XmlBeanDefinitionReader對象,對其設置了Environment對象(具體過程可以上一篇)等后,調用XmlBeanDefinitionReader進行解析。直接跟蹤進去,得到如下內容:

Spring BeanDefinition的加載過程

?其中參數inputSource為XML配置文件,Resource則該配置文件的描述,主要描述了該配置文件在classpath中的位置和可用于加載該配置文件的加載器。doLoadDocument方法比較簡單,主要是加載指定的配置文件,返回一個JDK內置的XML解析Document對象,以便于解析XML DOM節點。

?重點看下registerBeanDefinitions方法,如下:

Spring BeanDefinition的加載過程

?該方法最終委托給了BeanDefinitonDocumentReader來完成Bean的解析。在這之前,初始化了一系列相關對象。包括:

  1. 使用DefaultBeanDefinitionDocumentReader作為BeanDefinitionDocumentReader接口的實現

  2. 創建了一個XmlReaderContext用于保存解析過程中使用到的各個相關對象,如資源描述對象Resource、ReaderEventListener事件監聽器、XmlBeanDefinitionReader以及NamespaceHandlerResolver命名空間解析器。其中劃重點的是DefaultNamespaceHandlerResolver,該類完成了自定義XML格式的解析,后面會有講解。

?初始相關對象后便將解析過程委托給了DefaultBeanDefinitionDocumentReader來進行處理,該類的重點為parseBeanDefinitions方法,在調用該方法前,先初始化了一個BeanDefinitionParserDelegate對象,如下:

Spring BeanDefinition的加載過程

?并將該delegate對象傳入了parseBeanDefinitions方法。BeanDefinitionParserDelegate主要提供了命名空間為http://www.springframework.org/schema/beans(下面簡寫為beans空間)的XML文件解析過程。該命名空間定義了4個主要的XML標簽,分別為beansbeanimportalias以及這些標簽對應的屬性,如下為該命名空間的示例,定義了一個基礎的Bean。

Spring BeanDefinition的加載過程

?需要注意的是,上面在初始化BeanDefinitionParserDelegate后會先解析XML上<beans>標簽上的默認屬性,包括:default-lazy-initdefault-mergedefault-autowiredefault-dependency-checkdefault-autowire-candidatesdefault-init-methoddefault-destroy-method這些全局屬性。

?下面看下parseBeanBefinitoins方法:

Spring BeanDefinition的加載過程

?該方法會對當前節點所屬命名空間進行判斷,分為默認命名空間和自定義命名空間,其中默認命名空間指的是上面提到的beans空間。對于默認命名空間,會逐一解析每個DOM子節點,判斷子節點的命名空間,最終委托給兩個方法:處理默認命名空間的parseDefaultElement方法和處理自定義命名空間的parseClustomElement方法。

Spring BeanDefinition的加載過程

?parseDefautlElement方法如上, 對beans空間定義的各個標簽分別進行了處理:

  1. 解析import標簽時,會讀取resource屬性指定的配置文件,加載后再解析該文件中的bean定義。

  2. 解析alias標簽時,讀取標簽的name和alias屬性,添加到BeanRegistry緩存中。

  3. 解析bean標簽時,直接委托給BeanDefinitionParserDelegate來處理,過程為:

    對于步驟3.d,處理過程為:

    1. 獲取class屬性值

    2. 獲取parent屬性值

    3. 初始化GenericBeanDefinition實例

    4. 解析bean節點的屬性,設置到BeanDefinition中,包括:scopeabstractlazy-initautowireddependency-checkautowire-candidateprimaryinit-methoddestroy-methodfactory-methodfactory-bean

    5. 解析description子節點,獲取值設置bean的描述內容

    6. 解析meta子節點列表,獲取key、value值設置附加元數據信息

    7. 解析lookup-method子節點列表,獲取name、bean值設置方法注入信息

    8. 解析replaced-method子節點列表,獲取值設置需要動態代理的方法信息

    9. 解析constructor-arg子節點列表,獲取值設置構造參數信息

    10. 解析property子節點列表,獲取值設置屬性信息

    11. 解析qualifier子節點列表,獲取值進行設置

    12. 獲取id屬性值作為beanName

    13. 獲取name屬性值作為aliases,該屬性值可以配置多個,以 , 或者 ; 符進行分割,將作為該bean的別名使用;若id值為空,且name不為空,則使用第一個name值作為id值

    14. 檢查beanName和aliases的唯一性

    15. 解析bean其他配置,生成GenericBeanDefinition對象

    16. 若beanName為空,則為其分配一個

?上面解析完bean的配置后,會再處理子節點中其他命名空間的配置,使用NamespaceHandler的decorate方法,用以修改Bean定義內容,這部分將使用下面的內容,放在后面一起講。

  1. 解析beans標簽時,會進行遞歸處理

?如上,默認命名空間主要用于解析bean的定義,經過上面的處理,bean定義的解析就已經完成,會將實例對象注冊到上下文中進行保存

?下面介紹parseClustomElement方法,顧名思義,該方法主要用來處理自定義命名空間的XML標簽的,可以當做是spring XML配置處理的一種擴展手段,如下,為該方法的內容:

Spring BeanDefinition的加載過程

?主要委托給了NamespaceHandlerResolver,通過查找到對應節點對應命名空間的Handler,調用該Handler的parse方法進行處理。

?前面說過,NamespaceHandlerResolver使用了DefaultNamespaceHandlerResolver作為實現,跟蹤resolve方法進去如下:

Spring BeanDefinition的加載過程

?過程為:

  1. 獲取已有的Handler處理列表,返回結果為一個Map,Key為XML命名空間,值可能為代表對應Handler類型的Spring對象或者已經實例化后的Handler對象,取決于之前是否已經調用過

  2. 若指為Handler對象,則直接返回

  3. 若為String對象,表明未初始化過,則初始化該類,并執行init初始化方法,然后將其重新返回Map中

?對于第(1)步中Handler處理列表的獲取,Spring會掃描classpath中所有位于META-INF中的spring.handlers配置文件,將所有內容讀取到一個Map中并返回。

Spring BeanDefinition的加載過程

?如上,為spring-context模塊提供的spring.handlers文件,提供了該模塊自定義命名空間標簽的支持。如下為自定義命名空間的例子:

Spring BeanDefinition的加載過程

?主要引入了context空間的spring-configured標簽和annotation-config標簽。

?至此,介紹了XML配置下的bean解析。

二、注解配置

?下面介紹Spring以注解的方式進行bean加載的過程,如下,為開啟注解加載所需要的配置:

Spring BeanDefinition的加載過程

?根據前面的內容,component-scanhttp://www.springframework.org/schema/context命名空間中的標簽,處理對象在spring-context模塊的spring.handlers文件中定義,對應的是類org.springframework.context.config.ContextNamespaceHandler,如下:

Spring BeanDefinition的加載過程

?查看該類,可以知道,component-scan由ComponentScanBeanDefinitionParser處理,如下:

Spring BeanDefinition的加載過程

?主要過程為:

  1. 獲取base-package屬性內容賦值給basePackage

  2. 替換basePackage中的占位符內容

  3. 根據 , ; \t \n 分割符分割basePackage,得到多個包路徑

  4. 解析component-scan配置內容,返回ClassPathBeanDefinitionScanner對象

    1. 解析設置use-default-filters參數

    2. 解析設置resource-pattern參數

    3. 解析設置name-generator參數

    4. 解析設置scope-resolver、scoped-proxy等參數

    5. 解析設置include-filterexclude-filter等參數, ClassPathBeanDefinitionScanner對象再初始化時默認增加了org.springframework.stereotype. Component、javax.annotation.ManagedBean和javax.inject.Named幾種注解

  5. 調用ClassPathBeanDefinitionScanner的doScan方法執行掃描,將符合的類并注冊到上下文中然后返回

  6. 解析annotation-config參數,如果為true(默認為true)則自動注冊一系列用于后置解析的注解處理類定義到上下文中 這里重點看下第(5)步和第(6)步

?第(5)執行掃描時,會遍歷第(3)步返回的所有路徑,對于每個路徑,會調用父類ClassPathScanningCandidateComponentProvider的findCandidateComponents方法,返回該路徑下所有符合要求的Bean,如下:

Spring BeanDefinition的加載過程

?ClassPathScanningCandidateComponentProvider會找到指定路徑所有的類,包裝為Resource[]對象,對于每個Resource,會使用SimpleMetadataReaderFactory工廠類為每個Resouce對象新建一個SimpleMetadataReader對象,該對象用于解析類的信息,需要注意的是,在初始化SimpleMetadataReader對象的時候就會執行解析動作,將結果存為ClassMetadata數據和AnnotationMetadata數據,前者用于存儲類的定義信息,包括類名,是否接口,包含的屬性等信息,后者則包含所有的注解信息。獲取SimpleMetadataReader對象后,會判斷該類是否符合component-scanner定義的include-filterexclude-filter中定義的內容,注意,默認包含了@Component等對象,所以默認會加載所有有@Component注解且所有有@Component元注解注解(如@Service@Repository)的類。若符合要求,則將該類包裝為ScannedGenericBeanDefinition對象,同時會檢查該類不能為一個接口且不能依賴一個內部非靜態類,若符合,則添加到待返回列表中。

?執行完上面的findCandidateComponents方法后,會為其分配一個beanName,用于內部使用,之后會調用AnnotationConfigUtils的processCommonDefinitionAnnotations方法,該方法會對上面返回的BeanDefinition解析一些基本的注解屬性并進行設置,包括@Lazy@Primary@DependsOn@Role@Description。完成該步后會判斷該bean是否已經存在,若不存在,則添加到上下文中。

?第(6)步的代碼如下:

Spring BeanDefinition的加載過程

?重點在后半部分,會調用AnnotationConfigUtils的registerAnnotationConfigProcessors方法,該方法添加了一系列用于后置解析的注解處理類定義到上下文中,包括:

  1. 添加ConfigurationClassPostProcessor處理器(BeanDefinitionRegistryPostProcessor),添加@Configuration功能,對應bean為org.springframework.context.annotation.internalConfigurationAnnotationProcessor

  2. 添加AutowiredAnnotationBeanPostProcessor處理器(SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor),添加@Autowired@Value功能,對應bean為org.springframework.context.annotation.internalAutowiredAnnotationProcessor

  3. 添加RequiredAnnotationBeanPostProcessor處理器(SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor),添加@Required功能,對應bean為org.springframework.context.annotation.internalRequiredAnnotationProcessor

  4. 添加CommonAnnotationBeanPostProcessor處理器(InstantiationAwareBeanPostProcessor 、DestructionAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor、BeanPostProcessor),添加@PostConstruct@PreDestroy功能,對應bean為org.springframework.context.annotation.internalCommonAnnotationProcessor

  5. 添加PersistenceAnnotationBeanPostProcessor處理器(InstantiationAwareBeanPostProcessor、DestructionAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor),添加@PersistenceUnit@PersistenceContext功能,對應bean為org.springframework.context.annotation.internalPersistenceAnnotationProcessor

  6. 添加EventListenerMethodProcessor,添加@EventListener功能,對應bean為org.springframework.context.event.internalEventListenerProcessor

  7. 添加DefaultEventListenerFactory,對應bean為org.springframework.context.event.internalEventListenerFactory

?以上各個bean在添加前都會先判斷是否已經存在改定義,若不存在才增加,因而可以通過在添加相應bean的方式,修改對應的處理功能。

?PS:第(6)步添加注解后置處理的方法其實也是annotation-config這個標簽功能的主要處理方法。由上可知annotation-config的處理類為AnnotationConfigBeanDefinitionParser,該類內部其實也是調用了AnnotationConfigUtils的registerAnnotationConfigProcessors方法來完成注解的功能,具體代碼如下:

Spring BeanDefinition的加載過程

三、接口回調

?結合之前Spring啟動的內容,接上上面的內容,可以得到如下的接口回調順序

Spring BeanDefinition的加載過程

?因為InstantiationAwareBeanPostProcessor、DestructionAwareBeanPostProcessor等接口繼承自MergedBeanDefinitionPostProcessor接口,MergedBeanDefinitionPostProcessor接口繼承自BeanPostrProcessor,實現類上存在重疊,這里先根據講解順序排序。

到此,相信大家對“Spring BeanDefinition的加載過程”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

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

AI

濮阳市| 来安县| 伊金霍洛旗| 胶南市| 金沙县| 柞水县| 公安县| 乌兰浩特市| 天长市| 新绛县| 同心县| 英德市| 历史| 治县。| SHOW| 大丰市| 玛多县| 桦甸市| 雷波县| 城步| 原平市| 禄丰县| 岳阳县| 白玉县| 吴堡县| 定西市| 台中县| 元氏县| 白水县| 普安县| 栖霞市| 莲花县| 光山县| 罗源县| 阿拉善左旗| 安平县| 岑巩县| 蓬莱市| 闸北区| 泸西县| 济宁市|