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