Spring源碼剖析4:懶加載的單例Bean獲取過程分析

本文轉自五月的倉頡 https://www.cnblogs.com/xrq730

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內容請到我的倉庫裏查看

https://github.com/h2pl/Java-Tutorial

喜歡的話麻煩點下Star哈

文章將同步到我的個人博客:

www.how2playlife.com

本文是微信公衆號【Java技術江湖】的《Spring和SpringMVC源碼分析》其中一篇,本文部分內容來源於網絡,爲了把本文主題講得清晰透徹,也整合了很多我認爲不錯的技術博客內容,引用其中了一些比較好的博客文章,如有侵權,請聯繫作者。

該系列博文會告訴你如何從spring基礎入手,一步步地學習spring基礎和springmvc的框架知識,並上手進行項目實戰,spring框架是每一個Java工程師必須要學習和理解的知識點,進一步來說,你還需要掌握spring甚至是springmvc的源碼以及實現原理,才能更完整地瞭解整個spring技術體系,形成自己的知識框架。

後續還會有springboot和springcloud的技術專題,陸續爲大家帶來,敬請期待。

爲了更好地總結和檢驗你的學習成果,本系列文章也會提供部分知識點對應的面試題以及參考答案。

如果對本系列文章有什麼建議,或者是有什麼疑問的話,也可以關注公衆號【Java技術江湖】聯繫作者,歡迎你參與本系列博文的創作和修訂。

<!-- more -->

前言

xml的讀取應該是Spring的重要功能,因爲Spring的大部分功能都是以配置做爲切入點的。

       我們在靜態代碼塊中讀取配置文件可以這樣做:

   //這樣來加載配置文件    
   XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml")); 

       (1)XmlBeanFactory 繼承 AbstractBeanDefinitionReader ,使用ResourceLoader 將資源文件路徑轉換爲對應的Resource文件。

       (2)通過DocumentLoader 對 Resource 文件進行轉換,將 Resource 文件轉換爲 Document 文件。

       (3)通過實現接口 BeanDefinitionDocumentReader 的 DefaultBeanDefinitionDocumentReader 類對Document 進行解析,並且使用 BeanDefinitionParserDelegate對Element進行解析。

step1:

bb0bf7543226c4ada238d93363f864d39da8e3e8

     在平常開發中,我們也可以使用Resource 獲取 資源文件:

  Resource resource = new ClassPathResource("application.xml");
  InputStream in = resource.getInputStream();

step2:

13bd511377c0957e4ef8daebdf457585a9acabea

      在資源實現加載之前,調用了 super(parentBeanFactory) --  /*Ignore the given dependency interface for autowiring.(忽略接口的自動裝配功能)/

      調用XmlBeanDefinitionReader 的 loadBeanDefinitions()方法進行加載資源:

      (1) 對Resource資源進行編碼

      (2) 通過SAX讀取XML文件來創建InputSource對象

      (3) 核心處理

7613f54877fef111ccbe68f2c3a96a9588029fb3

       可以很直觀的看出來是這個function是在解析xml文件從而獲得對應的Document對象。

4b3425c37260bbb7e68ace81867259089871a0db

      在doLoadDocument方法裏面還存一個方法getValidationModeForResource()用來讀取xml的驗證模式。(和我關心的沒什麼關係,暫時不看了~)

      轉換成document也是最常用的方法:

     869effccb2e4f7b69e0b53d17fe0a2b50044d61b

step3 : 我們已經step by step 的看到了如何將xml文件轉換成Document的,現在就要分析是如何提取和註冊bean的。

            /*Register the bean definitions contained in the given DOM document/

2daf08bfd105a15d3c5eaf411fdb0083b3969f81

參數doc是doLoadBeanDefinitions()方法傳進來的  loadDocument 加載過來的。這邊就很好的體現出了面向對象的單一全責原則,將邏輯處理委託給單一的類去處理。

在這邊單一邏輯處理類是:  BeanDefinitionDocumentReader

核心方法:  <font color="#FF0000">documentReader.registerBeanDefinitions(doc, createReaderContext(resource));</font>

<font color="#FF0000">46ca5d8a7167fb010024f79e1f334820d7d2080a</font>

<font color="#FF0000">開始解析:</font>

<font color="#FF0000">43eb5d219f00c7b5c99c0eed0828b9ff2550af41</font>


在Spring的xml配置中有兩種方式來聲明bean:

     一種是默認的:  <bean id = " " class = " " />

     還有一種是自定義的:  < tx : annotation-driven / >

fecfb37a9f121df42d5754f6fdf99367539936c6

通過xml配置文件的默認配置空間來判斷:http://www.springframework.org/schema/beans

對於默認標籤的解析:

2b3bba761875a27d4ca52d72e76de934a90e51a1

對Bean 配置的解析:

8dac08836a4c27f90d15355991774186886ef141

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  返回BeanDefinitionHolder

f163a5df0d4ea8e105526fa7ef39547a1c188047

b93c6e1209359777b877f17e203e6226a269f4e0

這邊代碼大致看下來:

  1. 提取元素中的id和name屬性
  2. 進一步解析將其他屬性封裝到 BeanDefinition 的實現類中
  3. 如果沒有指定beanName 變使用默認規則生成beanName
  4. 封裝類BeanDefinitionHolder

可以先了解一下  BeanDefinition  這個類的作用。

      BeanDefinition是一個接口,對應着配置文件中<bean>裏面的所有配置,在Spring中存在着三個實現類:

917b789f984dee75d3b2748d885dcdd6541df8fe

      在配置文件中,可以定義父<bean>和子<bean>,父<bean>是用RootDefinition來表示,子<bean>是用ChildBeanDefinition來表示。

      Spring 通過BeanDefiniton將配置文件中的<bean>配置信息轉換爲容器內部表示,並且將這些BeanDefinition註冊到BeanDefinitonRegistry中。

Spring容器的BeanDefinitonRegistry就像是Spring配置信息的內存數據庫,主要是以map的形式保存的。

     因此解析屬性首先要創建用於承載屬性的實例:

83cf6bccba49fb369d0221e7970187041da349f0

然後就是各種對屬性的解析的具體方法:

89c0d5422e0495347f18fa03110bfb2afa255493

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章