天天看點

Spring的IOC容器建立過程深入剖析

前言

   本次對于Spring的IOC容器的建立過程是基于其源碼進行研究分析的,主要涉及BeanFactory的建立過程,Bean的解析與注冊過程,Bean執行個體化的過程以及諸如ClassPathXmlApplicationContext的IOC建構過程。

IOC容器建立過程

   在Spring中,三大核心元件Context、Bean以及Core中,Context将Bean和Core結合起來了,進而使得三大核心元件互相作用,共同建構整個Spring的基礎。在Spring中,ApplicationContext的子類AbstractApplicationContext的refresh()是建構Bean的入口點,它設定了建立IOC的模闆方法。子類建立IOC最終都會委派到該方法進行建立的。

   AbstractApplicationContext的refresh()源代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

<code>public</code> <code>void</code> <code>refresh() </code><code>throws</code> <code>BeansException, IllegalStateException {</code>

<code>synchronized</code> <code>(</code><code>this</code><code>.startupShutdownMonitor) {</code>

<code>   </code><code>// 準備上下文用于重新整理</code>

<code>   </code><code>prepareRefresh();</code>

<code>   </code><code>// 建立BeanFactory,Bean定義的解析與注冊</code>

<code>   </code><code>ConfigurableListableBeanFactory beanFactory =     obtainFreshBeanFactory();</code>

<code>  </code><code>// 為該上下文配置已經生成的BeanFactory</code>

<code>  </code><code>prepareBeanFactory(beanFactory);</code>

<code>    </code><code>try</code> <code>{</code>

<code>    </code><code>//可以調用使用者自定義的BeanFactory來對已經生成的BeanFactory進行修改</code>

<code>    </code><code>postProcessBeanFactory(beanFactory);</code>

<code>    </code><code>invokeBeanFactoryPostProcessors(beanFactory);</code>

<code>    </code><code>//可以對以後再建立Bean執行個體對象添加一些自定義操作</code>

<code>    </code><code>registerBeanPostProcessors(beanFactory);</code>

<code>    </code><code>//初始化資訊源</code>

<code>    </code><code>initMessageSource();</code>

<code>    </code><code>//初始化事件</code>

<code>    </code><code>initApplicationEventMulticaster();</code>

<code>    </code><code>//初始化在特定上下文中的其它特殊Bean</code>

<code>    </code><code>onRefresh();</code>

<code>    </code><code>registerListeners();</code>

<code>    </code><code>//Bean的真正執行個體化,建立非懶惰性的單例Bean</code>

<code>    </code><code>finishBeanFactoryInitialization(beanFactory);</code>

<code>    </code><code>finishRefresh();</code>

<code>   </code><code>}</code><code>catch</code> <code>(BeansException ex) {</code>

<code>    </code><code>destroyBeans();</code>

<code>    </code><code>cancelRefresh(ex);</code>

<code>    </code><code>throw</code> <code>ex;</code>

<code>   </code><code>}</code>

<code>}</code>

   整個方法代碼使用的就是模闆方式設計模式,工廠方法模式等,定義了整個BeanFactory建構過程。建構BeanFactory,以便于産生所需要的Bean對象;注冊可能感興趣的事件;建立Bean執行個體對象;觸發被監聽的事件。IOC容器就是一個Context組合另外兩個核心元件而形成的Bean的關系網,是Bean的大容器

   在解析IOC容器的建立過程中,以下面兩行代碼為原型,來穿插着解析該IOC的建立過程。這是一種常見的IOC容器的建立過程,僅僅通過new一個ClassPathXmlApplicationContext就完成了IOC建立。

<code>ApplicationContext ctx = </code><code>new</code> <code>ClassPathXmlApplicationContext(</code><code>"beans.xml"</code><code>);</code>

<code>    </code><code>UserService service = ctx.getBean(</code><code>"ser"</code><code>,UserService.</code><code>class</code><code>);</code>

ClassPathXmlApplicationContext的繼承關系如下

<a target="_blank" href="http://blog.51cto.com/attachment/201307/080808327.jpg"></a>

   當我們new一個ClassPathXmlApplicationContext,為其傳遞一個bean配置檔案的位址,其最終調用的構造器如下:

<code>public</code> <code>ClassPathXmlApplicationContext(String[] configLocations, </code><code>boolean</code> <code>refresh, ApplicationContext parent)</code>

<code>{</code>

<code>        </code><code>super</code><code>(parent);</code>

<code>        </code><code>//設定配置檔案的位置configLocations</code>

<code>    </code><code>setConfigLocations(configLocations);</code>

<code>    </code><code>if</code> <code>(refresh) {</code>

<code>        </code><code>//這裡就是調用了父類AbstractApplicationContext的refresh</code>

<code>        </code><code>//也證明了refresh是建構IOC的入口點</code>

<code>    </code><code>refresh();</code>

<code>    </code><code>}</code>

   從源代碼可以看出,第一句,最終會調用繼承關系中的AbstractApplicationContext構造器,具體做的工作就是傳回一個PathMatchingResourcePatternResolver。

   第二句,設定配置檔案的位置,調用父類AbstractRefreshableConfigApplicationContext的方法,設定configLocations的值。利用這種構造器建立,并沒有設定其屬性configResources的值,則為null。(這個在下面講IOC建立的地方需要用到)。

   第三句,在該構造器中調用了父類AbstractApplicationContext的refresh方法,進而進行IOC的真正建立了。

BeanFactory建立:

    BeanFactory建立是在obtainFreshBeanFactory方法中完成的。在該方法中,會調用子類實作了refreshBeanFactory的方法,重新整理子類,如果BeanFactory存在則重新整理,如果不存在就建立一個新的BeanFactory。最終預設的建立BeanFactory就是由DefaultListableBeanFactory來完成的。

<a target="_blank" href="http://blog.51cto.com/attachment/201307/082438684.jpg"></a>

   這是一個BeanFactory建立的時序圖,在該時序圖中包含了BeanFactory建立的過程,還有Bean定義的解析、加載以及注冊過程,關于Bean定義的解析與加載注冊過程,會在下面以詳細的時序圖來解釋的。這裡隻是refresh()方法中,調用refreshBeanFactory()來建構BeanFactory的标準初始化過程。我們ClassPathXmlApplicationContext的BeanFactory就是遵循這樣的構造過程。

Bean解析注冊過程:

   在上面的時序圖中,最右邊可以看到對Bean的定義進行加載與解析和注冊處理,

   在AbstractXmlApplicationContext中調用loadBeanDefinitions,這裡最終是交給XmlBeanDefinitionReader來加載指定的bean定義。AbstractXmlApplicationContext類的loadBeanDefinitions()方法源碼如下:

<code>protected</code> <code>void</code> <code>loadBeanDefinitions(XmlBeanDefinitionReader reader) </code><code>throws</code> <code>BeansException, IOException {</code>

<code>        </code><code>Resource[] configResources = getConfigResources();</code>

<code>        </code><code>if</code> <code>(configResources != </code><code>null</code><code>) {</code>

<code>            </code><code>reader.loadBeanDefinitions(configResources);</code>

<code>        </code><code>}</code>

<code>        </code><code>String[] configLocations = getConfigLocations();</code>

<code>        </code><code>if</code> <code>(configLocations != </code><code>null</code><code>) {</code>

<code>            </code><code>reader.loadBeanDefinitions(configLocations);</code>

   這個方法就是根據指定的XmlBeanDefinitionReader來加載我們的Bean定義,并且最其進行解析和注冊處理。

   在這裡,一般隻會執行其中的一個if語句,這裡我們的ClassPathXmlApplicationContext,前面已經說過,new的過程隻設定了configLocations值,并沒有設定configResources屬性值,則就會直接執行第二個if語句。這裡就會調用AbstractBeanDefinitionReader的一個重載方法loadBeanDefinitions方法,這個最終是調用子類XmlBeanDefinitionReader的loadBeanDefinitions()

    具體的标準Bean解析注冊過程如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201307/083901357.jpg"></a>

其它初始化與準備過程:

   在BeanFactory建立完成後,我們定義的Bean僅僅是已經被解析和注冊了,實際上還沒真正的建立他們的執行個體對象。當obtainFreshBeanFactory()方法傳回後,就會為該上下文配置剛剛已經生成的BeanFactory,我們要想擴充Spring的IOC容器,則就可以在下面的三個代碼處進行自定義操作

<code>postProcessBeanFactory(beanFactory);</code>

<code>invokeBeanFactoryPostProcessors(beanFactory);</code>

<code>registerBeanPostProcessors(beanFactory);</code>

   前兩句主要就是當一個BeanFactory建立完成後,我們可以調用自定義的BeanFactory,對已經建立的配置資訊進行修改。最後一句就是在以後的Bean的執行個體化過程中,可以定義一些自定義操作。

   接下來就是就是初始化上下文的資訊源,應用程式事件,其他特殊bean。

Bean執行個體對象建立過程:

   在該refresh中,最後會調用finishBeanFactoryInitialization來完成Bean的執行個體對象建立過程。具體的Bean建立時序圖如下:

   在Bean的建立過程,有個特殊的FactoryBean,這是個特殊的Bean他是個工廠Bean,可以産生Bean的Bean,這裡的産生Bean是指 Bean的執行個體,如果一個類繼承FactoryBean使用者可以自己定義産生執行個體對象的方法隻要實作他的getObject方法。在Spring内部這個Bean的執行個體對象是FactoryBean,通過調用這個對象的getObject方 法就能擷取使用者自定義産生的對象,進而為Spring提供了很好的擴充性。Spring擷取FactoryBean本身的對象是在前面加上&amp;來完成的。

   在我們的示例代碼的第二行,當使用getBean的時候擷取Bean的時候具體流程如下:

   1,它會調用抽象方法getBeanFactory()

   2,最終調用AbstractRefreshableApplicationContext的getBeanFactory,是final的方法。

本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1244016