Spring之IoC容器

    spring是一個極爲龐大和豐富的框架,筆者在此並不想從零開始的去講解她。關於spring的基礎概念等希望讀者自行百度。文中會涉及到很多spring的源代碼,我並不想在此處大量copy出來,有興趣的讀者可以自己查看學習。再一點,閱讀本文之前,讀者若有一些spring的開發經驗或許能更好的理解本文及spring原理。本文是在閱讀了前輩大牛《SPRING技術內幕:深入解析SPRING架構與設計原理》之後撰寫的,讀者會在本文中找到很多書中的影子。
    
    Spring IoC容器的具體使用是構建在BeanFactory和ApplicationContext的設計與實現之上的。首先通過一個圖片來了解他們之間的聯繫與區別,然後再仔細研究細節:
       

    從圖中可以很明顯的看出,BeanFactory作爲基本容器在Spring IoC中的地位以及ApplicationContext作爲高級形態的存在。容器是用來裝載物品的,在spring中裝載的就是大家熟識的bean,但我們知道,在使用spring時bean的定義或指定是在xml中配置的。spring是怎樣從配置文件中獲取這些bean的,並且怎樣將屬性值“注入”到這些實例中的?在這之中,spring有一個很重要的數據結構BeanDefinition,它抽象了我們對bean的定義,是讓容器起作用的主要數據結構,spring中利用BeanDefinition來管理spring中各對象及他們之間的相互依賴關係。
    spring_IoC容器初始化的工作流程:
    Resource資源的定位(即BeanDefinition資源的定位)---->BeanDefinition載入---->BeanDefinition註冊
    可以說,IoC容器的初始化就是對資源配置文件中的bean進行解析和和裝載的過程。此處先提醒一下,IoC的初始化過程不包括bean依賴注入的實現。依賴注入一般發生在第一次getBean時(bean的lazyinit屬性可改變bean的依賴注入過程)。
    下面以FileSystemXmlApplicationContext爲例來詳細說明ApplicationContext的設計原理,首先還是來了解一下FileSystemXmlApplicationContext的繼承體系:


    從圖可以看到,FileSystemXmlApplicationContext通過繼承AbstractApplictionContext實現了ResourceLoader讀入Resource定義的BeanDefinition的能力。查看FileSystemXmlApplicationContext類的源代碼可以知道,這個IoC容器是由構造方法中的refresh()開啓的,它的getResourceByPath()就是資源的定位。在myeclipse中查看它的調用關係及相關代碼,可以得到下面的調用過程:
                                                        refreshBeanFactory()                                                                getReourceByPath()
    FileSystemXmlApplictionContext------------------>AbstractRefreshableApplicationContext-------------------->FileSystemResource

調用完成後返回FileSystemResource實例對象,通過這個對象完成BeanDefinition的定位。如果是其他的ApplictionContext則會返回相應種類的Resource。
容器的啓動是由refresh()方法開始的,這個refresh方法具體實現是在FileSystemXmlApplicationContext的基類AbstractApplicationContext中實現的。我們看一下具體的調用過程:



    在這個過程中BeanDefinitionParserDelegate的parseBeanDefinitionElement()方法可以仔細查看源代碼,它是解析具體bean的地方。至此完成了BeanDefinition的載入解析
    接下來看看BeanDefinition的註冊:還記得解析中的XmlDefinitionReader吧,完成BeanDefinition解析後緊接着就是註冊了,註冊是由registerBeanDefinitions()完成的。


    接下來繼續看註冊的具體動作,DefualtListableBeanFactory實現了BeanDefinitionRegistry接口,這個接口完成向容器的註冊,註冊的過程並不複雜,主要就是將BeanDefinition設置到HashMap中去,讀者可以去仔細看看registerBeanDefinition()這個方法。
    至此,容器初始化的工作已完成,讀者可以在源代碼中看看具體的實現過程。回顧一下這個初始化的過程,它的主要工作是在IoC容器中建立BeanDefinition數據映射。有了這些映射信息作爲基礎,後面我們再在IoC容器中完成依賴注入。
    
    首先,依賴注入的過程是用戶第一次向容器getBean()時觸發的(lazy-init屬性預實例化的bean除外)。從AbstractBeanFactyory類的getBean()的實現來看,這就是依賴注入的入口。下面還是通過時序圖來看看這個依賴注入的過程:


    依賴注入過程中有兩個很特別的方法,createBeanInstance和populateBean.createBeanInstance方法中生成了Bean所包含的java對象,populateBean則把這些Bean對象的依賴關係設置好。依賴注入的發生是在BeanWrapper的setPropertyValues中實現的,通過這一系列的複雜動作,bean屬性的依賴注入便完成了。

    總結一下文章,主要是講IoC容器初始化到依賴注入的過程,其中IoC容器初始化又分爲BeanDefinition的定位、載入和注入三個步驟。在整個過程中還設計到一系列的實現類和方法,讀者需要自己去瀏覽源代碼,理解彼此之間的調用關係。另外,本文是以其中一個具體的FileSystemXmlApplicationContex爲例來講解SpringIoC容器框架設計及實現的,其它的具體實現讀者可以相對應的去查看分析源代碼。最後,再次感謝計文柯老師《SPRING技術內幕:深入解析SPRING架構與設計原理》的這本書,後續筆者還會繼續撰寫關於Spring的文章,例如SpringAOP的實現,Spring的事務處理實現等。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章