Spring配置文件裝配bean大體流程

容器啟動(dòng)的模板方法

1. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

此方法主要完成對(duì)配置文件中bean定義解析為BeanDefinition的工作,并將BeanDefinition注冊(cè)到registry中.

1.1 刷新BeanFactory

1.1.1 若當(dāng)前已存在BeanFactory,對(duì)其進(jìn)行銷毀和關(guān)閉

1.1.2 創(chuàng)建DefaultListableBeanFactory作為默認(rèn)容器,設(shè)置容器的序列化id并定制一些屬性(allowBeanDefinitionOverriding和allowCircularReferences)

1.1.3 裝載BeanDefinition

1.1.3.1 構(gòu)造一個(gè)XmlBeanDefinitionReader,并對(duì)其進(jìn)行一些設(shè)置
1.1.3.2 BeanDefinition裝載工作委托給XmlBeanDefinitionReader來處理
  1. 獲取配置文件地址
  2. 循環(huán)處理每個(gè)配置文件地址來處理BeanDefinition的裝載
    ?2.1 通過ResourceLoader將配置文件地址解析為Resource
    ?2.2 通過Resource來裝載BeanDefinition
    ??2.2.1 將配置文件資源解析為Document
    ??2.2.2 構(gòu)造一個(gè)BeanDefinitionDocumentReader(實(shí)現(xiàn)類為DefaultBeanDefinitionDocumentReader),將Document解析解析為BeanDefinition并注冊(cè)的工作委托給這個(gè)DefaultBeanDefinitionDocumentReader處理.
    ??2.2.2.1 構(gòu)造一個(gè)BeanDefinitionParserDelegate,將Document中各個(gè)節(jié)點(diǎn)元素的解析處理工作委托給這個(gè)BeanDefinitionParserDelegate來完成.包括默認(rèn)命名空間節(jié)點(diǎn)元素的解析和自定義命名空間節(jié)點(diǎn)元素的解析(這部分為重點(diǎn),具體放到1.3深入總結(jié)).

1.2 獲取刷新后新的BeanFactory,并將其返回

1.3 默認(rèn)命名空間節(jié)點(diǎn)元素和自定義命名空間節(jié)點(diǎn)元素的解析

以默認(rèn)命名空間的<bean>標(biāo)簽解析為例

1.3.1 BeanDefinitionParserDelegate將Element解析為BeanDefinitionHolder

  • 處理beanName和alias
  • Element解析為AbstractBeanDefinition
    1. 生成一個(gè)GenericBeanDefinition(AbstractBeanDefinition的子類),記為bd
    2. 為bd設(shè)置一些屬性.如scope,lazy-init,depends-on,init-method等等等等.
    3. 解析該bean元素下的一些子元素屬性設(shè)置
    4. 構(gòu)造參數(shù)子元素解析(對(duì)應(yīng)以后的構(gòu)造注入,如<constructor-arg index="0" ref="t"/>)
    5. 屬性子元素解析(對(duì)應(yīng)以后的設(shè)值注入,如<property name="start" value="a"/>),重點(diǎn)分析一下這里屬性注入方式
      5.1 處理屬性或子元素(源碼注解:Should only have one child element: ref, value, list, etc.),生成相應(yīng)的對(duì)象并將其返回
      5.2 以上述返回的對(duì)象和屬性名構(gòu)造PropertyValue.(這個(gè)類很關(guān)鍵,xml配置bean的方式下,設(shè)值注入的每個(gè)屬性依賴就是通過每個(gè)PropertyValue來實(shí)現(xiàn)的)
      5.3 向MutablePropertyValues添加上述PropertyValue.(這是依賴注入另一個(gè)關(guān)鍵類,AbstractBeanDefinition內(nèi)部持有一個(gè)MutablePropertyValues屬性propertyValues,通過這個(gè)屬性保存所有的依賴,MutablePropertyValues內(nèi)部持有一個(gè)List<PropertyValue> propertyValueList,實(shí)際上就是將前面生成的每一個(gè)PropertyValue添加到這個(gè)list中)
  • 返回AbstractBeanDefinition

1.3.2 注冊(cè)BeanDefinition以及注冊(cè)別名alias

到這里只是完成了將配置文件中定義的bean解析為Spring為Bean專門定義的數(shù)據(jù)結(jié)構(gòu)BeanDefinition,還未完成實(shí)例化和依賴的注入,只是將數(shù)據(jù)解析和準(zhǔn)備完成.




2. invokeBeanFactoryPostProcessors(beanFactory);

實(shí)現(xiàn)BeanFactoryPostProcessor接口的后置處理器的處理邏輯調(diào)用,BeanFactoryPostProcessor是對(duì)BeanDefinition的后置處理(此時(shí)bean還未進(jìn)行實(shí)例化和依賴注入,只是以解析后的BeanDefinition形式存在)



3. registerBeanPostProcessors(beanFactory);

注冊(cè)BeanPostProcessor,這里只是注冊(cè),還未實(shí)際調(diào)用



4. finishBeanFactoryInitialization(beanFactory);

這里完成bean的實(shí)例化,依賴注入,后置處理等等一些列操作.關(guān)鍵方法beanFactory.preInstantiateSingletons();

4.1 獲取所有的注冊(cè)的beanName,循環(huán)遍歷處理以完成實(shí)例化和依賴注入

4.1.1 獲取BeanDefinition

4.1.2 對(duì)于滿足條件:非抽象&&單例&&非延遲初始化的BeanDefinition,通過getBean方法完成實(shí)例化并獲取Bean

4.1.2.1 從單例緩存中獲取實(shí)例
4.1.2.2 如果取得實(shí)例不為空,若該實(shí)例為普通Bean,直接返回;若為FactoryBean,嘗試從FactoryBean緩存中獲取,存在則返回,否則的話最終通過FactoryBean的getObject方法獲取對(duì)象,并存緩存.(getObjectForBeanInstance方法源碼注解:Get the object for the given bean instance, either the bean instance itself or its created object in case of a FactoryBean.)
4.1.2.3 如果取得實(shí)例為空(重點(diǎn)分支流程)
  • 獲取父容器,若滿足條件父容器不為空&&當(dāng)前容器不包含該beanName的BeanDefinition,返回調(diào)用父容器的getBean方法的結(jié)果,否則不執(zhí)行這一步,繼續(xù)向下執(zhí)行
  • 獲取BeanDefinition
  • 獲取解析后存于BeanDefinition中的依賴(String[]),循環(huán)處理每個(gè)依賴
    1. 判斷是否循環(huán)depends-on關(guān)系,是則拋出異常
    2. 注冊(cè)依賴
    3. 遞歸調(diào)用getBean方法,先處理依賴的Bean(也就是先遞歸到最底層處理沒有任何依賴的Bean,在一層一層返回上層處理,這樣保證了依賴的底層Bean會(huì)先被實(shí)例化)
  • 如果BeanDefinition中的數(shù)據(jù)記錄的該bean是單例的,那么最終通過createBean方法(該方法由AbstractAutowireCapableBeanFactory實(shí)現(xiàn))來完成Bean的初始化,依賴注入,各種后置處理等等工作(這里只分析單例情況,prototype情況不分析了)
    1. 為BeanPostProcessors提供返回代理而不是目標(biāo)bean實(shí)例的機(jī)會(huì).(源碼注釋:Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.)
      1.1 對(duì)InstantiationAwareBeanPostProcessor接口的實(shí)現(xiàn)類調(diào)用其前置方法postProcessBeforeInstantiation,只要有一個(gè)接口實(shí)現(xiàn)類的postProcessBeforeInstantiation方法調(diào)用成功(即返回的結(jié)果不為null),后面其他接口實(shí)現(xiàn)類就不再執(zhí)行
      1.2 在上面1.1執(zhí)行成功的前提下,執(zhí)行所有的BeanPostProcessor的后置處理方法postProcessAfterInitialization
    2. doCreateBean方法(重要方法)
      2.1 createBeanInstance方法,使用適當(dāng)?shù)膶?shí)例化策略為指定的bean創(chuàng)建新實(shí)例:工廠方法彤敛,構(gòu)造函數(shù)自動(dòng)裝配或簡(jiǎn)單實(shí)例化(源碼注釋:Create a new instance for the specified bean, using an appropriate instantiation strategy:factory method, constructor autowiring, or simple instantiation.).該方法返回一個(gè)BeanWrapper,BeanWrapper中通過一個(gè)內(nèi)部屬性object來持有bean,此時(shí)的bean只是初步創(chuàng)建,還未進(jìn)行依賴注入
      2.2 執(zhí)行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
      2.3 populateBean方法用來完成依賴注入
      ?2.3.1 獲取BeanDefinition的PropertyValues
      ?2.3.2 調(diào)用InstantiationAwareBeanPostProcessors的處理方法postProcessAfterInstantiation,為任何InstantiationAwareBeanPostProcessors提供在設(shè)置屬性之前修改bean狀態(tài)的機(jī)會(huì).例如,這可以用于支持現(xiàn)場(chǎng)注入的樣式(源碼注釋:Give any InstantiationAwareBeanPostProcessors the opportunity to modify the state of the bean before properties are set. This can be used, for example, to support styles of field injection.)
      ?2.3.3 autowireByName或者autowireByType,這里分析一下autowireByType
      ??2.3.3.1 找到需要依賴注入的屬性氮块,不包括基本類型和String等這種簡(jiǎn)單的類型
      ??2.3.3.2 處理依賴,獲取被注入bean
      ??2.3.3.3 將上述bean添加到MutablePropertyValues的propertyValueList中(從原List中遍歷去除同名PropertyValue以保證是同一個(gè)屬性,合并屬性并返回;若遍歷原List時(shí)沒有同一名稱的屬性,則直接添加到List中)
      ??2.3.3.4 調(diào)用InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法進(jìn)行一些后置處理(注解注入@autowired的實(shí)現(xiàn)就是通過這里AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法來實(shí)現(xiàn)的)
      ??2.3.3.5 applyPropertyValues應(yīng)用屬性,完成注入.
      2.4 initializeBean方法的執(zhí)行,初始化給定的bean實(shí)例,應(yīng)用工廠回調(diào)以及init方法和bean后處理器(源碼注釋:Initialize the given bean instance, applying factory callbacks as well as init methods and bean post processors.)
      ?2.4.1 invokeAwareMethod方法調(diào)用,完成一些Aware接口方法處理,BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
      ?2.4.2 BeanPostProcessor的postProcessBeforeInitialization處理方法
      ?2.4.3 invokeInitMethods方法調(diào)用,執(zhí)行一些init方法
      ?2.4.4 BeanPostProcessor的postProcessAfterInitialization處理方法




注:

Spring Bean的實(shí)例化和初始化兩個(gè)階段的主要作用:

1聘鳞、實(shí)例化Instantiation—-實(shí)例化的過程是一個(gè)創(chuàng)建Bean的過程,即調(diào)用Bean的構(gòu)造函數(shù),單例的Bean放入單例池中,可理解為createBeanInstance方法階段初步創(chuàng)建的bean.

2、初始化Initialization—-初始化的過程是一個(gè)賦值的過程,即調(diào)用Bean的setter,設(shè)置Bean的屬性,可理解為依賴注入階段

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锹雏,一起剝皮案震驚了整個(gè)濱河市巴比,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁遵,老刑警劉巖轻绞,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異榛丢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)挺庞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門晰赞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人选侨,你說我怎么就攤上這事掖鱼。” “怎么了援制?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵戏挡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我晨仑,道長(zhǎng)褐墅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任洪己,我火速辦了婚禮妥凳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘答捕。我一直安慰自己逝钥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布拱镐。 她就那樣靜靜地躺著艘款,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沃琅。 梳的紋絲不亂的頭發(fā)上哗咆,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音益眉,去河邊找鬼岳枷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的空繁。 我是一名探鬼主播殿衰,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼盛泡!你這毒婦竟也來了闷祥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤傲诵,失蹤者是張志新(化名)和其女友劉穎凯砍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拴竹,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悟衩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了栓拜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片座泳。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖幕与,靈堂內(nèi)的尸體忽然破棺而出挑势,到底是詐尸還是另有隱情,我是刑警寧澤啦鸣,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布潮饱,位于F島的核電站,受9級(jí)特大地震影響诫给,放射性物質(zhì)發(fā)生泄漏香拉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一中狂、第九天 我趴在偏房一處隱蔽的房頂上張望缕溉。 院中可真熱鬧,春花似錦吃型、人聲如沸证鸥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枉层。三九已至,卻和暖如春赐写,著一層夾襖步出監(jiān)牢的瞬間鸟蜡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工挺邀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揉忘,地道東北人跳座。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像泣矛,于是被迫代替她去往敵國(guó)和親疲眷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容