摘要:對(duì)于開發(fā)者來(lái)說,無(wú)疑是最常用也是最基礎(chǔ)的框架之一。概念上的東西還是要提一嘴的用容器來(lái)管理。和是容器的兩種表現(xiàn)形式。定義了簡(jiǎn)單容器的基本功能。抽象出一個(gè)資源類來(lái)表示資源調(diào)用了忽略指定接口的自動(dòng)裝配功能委托解析資源。
對(duì)于Java開發(fā)者來(lái)說,Spring無(wú)疑是最常用也是最基礎(chǔ)的框架之一。(此處省略1w字吹Spring)。相信很多同行跟我一樣,只是停留在會(huì)用的階段,比如用@Component寫一個(gè)組件、用@Autowired注入其他組件等等,但是不知道為什么可以這么做,Spring是怎么實(shí)現(xiàn)的。為了了解這些,我閱讀了《Spring源碼深度解析》,這本書講的很詳細(xì),但是因?yàn)椴襟E多而復(fù)雜容易記混,我就做了一下梳理,先呈現(xiàn)大致流程,但對(duì)每個(gè)步驟進(jìn)行詳細(xì)描述。
概念上的東西還是要提一嘴的:
Spring用IoC容器來(lái)管理Bean。
BeanFactory和ApplicationContext是SpringIoC容器的兩種表現(xiàn)形式。
BeanFactory定義了簡(jiǎn)單IoC容器的基本功能。
ApplicationContext實(shí)現(xiàn)了BeanFactory,且通過繼承MessageSource、ResourceLoader、ApplicationEventPublisher接口,添加了許多高級(jí)容器的特性。
這里以XmlBeanFactory為代表,看容器是怎么工作的。
新建一個(gè)XmlBeanFactory很簡(jiǎn)單,只需要你有一個(gè)符合格式的xml文件,里面用
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("test.xml"))
新建了一個(gè)ClassPathResource資源對(duì)象作為參數(shù)傳入XmlBeanFactory的構(gòu)造函數(shù)。
點(diǎn)進(jìn)XmlBeanFactory類,XmlBeanFactory會(huì)先調(diào)用父類構(gòu)造器,一直跟蹤到AbstractAutowireCapableBeanFactory,會(huì)看到調(diào)用了三次ignoreDependencyInterface用來(lái)忽略給定接口的自動(dòng)裝配功能(后面會(huì)提到);再調(diào)用this.reader.loadBeanDefinitions(Resource),用自己持有的XmlBeanDefinitionReader解析傳入的資源。所以最宏觀的三個(gè)步驟:
1、新建了一個(gè)ClassPathResource資源。抽象出一個(gè)資源類來(lái)表示資源;
2、調(diào)用了ignoreDependencyInterface忽略指定接口的自動(dòng)裝配功能;
3、委托XmlBeanDefinitionReader解析資源。
重點(diǎn)肯定在第三步了,點(diǎn)進(jìn)XmlBeanDefinitionReader,到loadBeanDefinitions(EncodedResource),先從
Resource獲取InputStream構(gòu)造成InputSource,作為參數(shù)調(diào)用doLoadBeanDefinitions(InputSource, Resource)開始真正的解析。所以第三步下面是兩個(gè)小步驟:
3.1、從Resource獲取輸入流;
3.2、調(diào)用doLoadBeanDefinitions繼續(xù)解析。
再看doLoadBeanDefinitions方法,主要是兩個(gè)方法,doLoadDocument(inputSource, resource)解析輸入流返回一個(gè)Document對(duì)象;registerBeanDefinitions(doc, resource)繼續(xù)解析Document返回解析的Bean數(shù)量,所以3.2下面是兩個(gè)步驟:
3.2.1、將資源解析成Document對(duì)象(這個(gè)步驟這邊就不展開了,有興自究);
3.2.2、解析Document,提取注冊(cè)Bean。
來(lái)到registerBeanDefinitions方法,這里創(chuàng)建了一個(gè)BeanDefinitionDocumentReader對(duì)象負(fù)責(zé)具體解析(是不是覺得又冒出了不認(rèn)識(shí)的類,框架就是這樣,遵循單一職責(zé)的原則,把一個(gè)集中的邏輯放到其他類中處理),它調(diào)用doRegisterBeanDefinitions(doc.getDocumentElement()),提取Document的root作為參數(shù)繼續(xù)解析,先查找解析profile屬性,將表示環(huán)境的屬性注冊(cè)到Environment;然后遍歷root每個(gè)子節(jié)點(diǎn),如果是默認(rèn)標(biāo)簽,調(diào)用parseDefaultElement進(jìn)行解析;如果是自定義標(biāo)簽,就調(diào)用delegate.parseCustomElement。所以3.2.2下面是這幾個(gè)步驟:
3.2.2.1、創(chuàng)建BeanDefinitionDocumentReader委托解析對(duì)象;
3.2.2.2、解析profile屬性到Environment;
3.2.2.3、遍歷子節(jié)點(diǎn),繼續(xù)解析默認(rèn)標(biāo)簽和自定義標(biāo)簽。
我們這邊主要分析默認(rèn)標(biāo)簽的解析,自定義的有興自究。首先根據(jù)標(biāo)簽類型選擇不同的處理方法,類型分別是import、alias、bean和beans。重點(diǎn)肯定是對(duì)bean標(biāo)簽的解析,進(jìn)入processBeanDefinition方法,我們看到里面先委托BeanDefinitionParserDelegate解析出一個(gè)持有bean信息的BeanDefinitionHolder;如果BeanDefinitionHolder不為空且子節(jié)點(diǎn)下存在自定義標(biāo)簽,再解析它們;然后對(duì)解析完成后的BeanDefinitionHolder進(jìn)行注冊(cè),注冊(cè)過程很簡(jiǎn)單就是將BeanDefinitionHolder持有的beanName和BeanDefinition的鍵值對(duì)、beanName和每個(gè)alias別名的鍵值對(duì)保存在容器中;最后發(fā)出bean已注冊(cè)完成的事件通知,所以這里分為4步:
3.2.2.3.1、委托BeanDefinitionParserDelegate解析返回BeanDefinitionHolder;
3.2.2.3.2、解析存在的自定義標(biāo)簽;
3.2.2.3.3、解析完成后注冊(cè);
3.2.2.3.4、發(fā)出響應(yīng)事件。
到了這里終于開始具體的解析,過程其實(shí)就是先解析出beanName、alias別名,然后把其余各種標(biāo)簽,如class、scope、lazy-init等屬性解析成用于屬性承載的BeanDefinition對(duì)象的成員變量,最后將beanName、alias數(shù)組和BeanDefinition封裝成BeanDefinitionHolder對(duì)象返回。具體各種屬性的功能和規(guī)則這邊就不展開了,有興自究。
對(duì)于import、alias和beans標(biāo)簽,簡(jiǎn)述一下:alias的解析和bean中的alias解析差不多,也是將每一個(gè)別名與beanName以map形式保存;impot可以導(dǎo)入其他配置文件,解析過程就是找到那個(gè)文件然后遞歸進(jìn)行解析;beans就是把多個(gè)bean標(biāo)簽包起來(lái),然后遍歷解析每一個(gè)bean標(biāo)簽。
畫一個(gè)流程圖作為總結(jié):
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/72507.html
摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來(lái)了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...
摘要:依賴注入是向某個(gè)類或方法注入一個(gè)值,其中所用到的原理就是控制反轉(zhuǎn)。但發(fā)現(xiàn)更多時(shí)間是在調(diào)和的源碼。里面就是從中取出這個(gè),完成控制反轉(zhuǎn)的??刂品崔D(zhuǎn)的優(yōu)點(diǎn)最后來(lái)以我個(gè)人觀點(diǎn)談?wù)効刂品崔D(zhuǎn)的優(yōu)點(diǎn)吧??刂品崔D(zhuǎn)為了降低項(xiàng)目耦合,提高延伸性。 本章開始來(lái)學(xué)習(xí)下Spring的源碼,看看Spring框架最核心、最常用的功能是怎么實(shí)現(xiàn)的。網(wǎng)上介紹Spring,說源碼的文章,大多數(shù)都是生搬硬推,都是直接看來(lái)的...
摘要:實(shí)例化時(shí),發(fā)現(xiàn)又依賴于。一些緩存的介紹在進(jìn)行源碼分析前,我們先來(lái)看一組緩存的定義??墒强赐暝创a后,我們似乎仍然不知道這些源碼是如何解決循環(huán)依賴問題的。 1. 簡(jiǎn)介 本文,我們來(lái)看一下 Spring 是如何解決循環(huán)依賴問題的。在本篇文章中,我會(huì)首先向大家介紹一下什么是循環(huán)依賴。然后,進(jìn)入源碼分析階段。為了更好的說明 Spring 解決循環(huán)依賴的辦法,我將會(huì)從獲取 bean 的方法getB...
摘要:在寫完容器源碼分析系列文章中的最后一篇后,沒敢懈怠,趁熱打鐵,花了天時(shí)間閱讀了方面的源碼。從今天開始,我將對(duì)部分的源碼分析系列文章進(jìn)行更新。全稱是,即面向切面的編程,是一種開發(fā)理念。在中,切面只是一個(gè)概念,并沒有一個(gè)具體的接口或類與此對(duì)應(yīng)。 1. 簡(jiǎn)介 前一段時(shí)間,我學(xué)習(xí)了 Spring IOC 容器方面的源碼,并寫了數(shù)篇文章對(duì)此進(jìn)行講解。在寫完 Spring IOC 容器源碼分析系列...
摘要:簡(jiǎn)介為了寫容器源碼分析系列的文章,我特地寫了一篇容器的導(dǎo)讀文章。在做完必要的準(zhǔn)備工作后,從本文開始,正式開始進(jìn)入源碼分析的階段。從緩存中獲取單例。返回以上就是和兩個(gè)方法的分析。 1. 簡(jiǎn)介 為了寫 Spring IOC 容器源碼分析系列的文章,我特地寫了一篇 Spring IOC 容器的導(dǎo)讀文章。在導(dǎo)讀一文中,我介紹了 Spring 的一些特性以及閱讀 Spring 源碼的一些建議。在...
閱讀 2813·2021-11-22 14:44
閱讀 560·2021-11-22 12:00
閱讀 3694·2019-08-30 15:54
閱讀 1589·2019-08-29 17:15
閱讀 1910·2019-08-29 13:50
閱讀 1126·2019-08-29 13:17
閱讀 3524·2019-08-29 13:05
閱讀 1192·2019-08-29 11:31