1. 程式人生 > >Spring系列筆記(一)--Bean裝載

Spring系列筆記(一)--Bean裝載

         Spring框架體系最基礎的功能依賴注入和AOP,首先根據框架的執行順序,介紹一下使用Spring框架時,例項的裝載過程。

一、解析配置檔案

        Spring通過配置檔案的形式將業務系統中複雜的例項組合、頻繁的例項建立、公共功能抽象等封裝出來,又容器載入配置檔案進行統一管理。比如ServiceA需要ServiceB的例項,簡單的做法是ServiceA中new一個ServiceB例項,使用Spring可以在ServiceA中直接注入ServieB的例項,由Spring進行例項的載入和初始化。    

        解析配置檔案的順序:

        1.首先需要讀取配置檔案如application.xml檔案,所以需要使用I/O流方式讀入記憶體;

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

        2.配置檔案中的命名方式,屬性欄位格式等都需要遵循一定的約定規範,所以配置檔案頭中需要dtd,xsd等路徑宣告解析檔案的原則,並且在解析過程中作為規則校驗配置資料的正確性,也可以有自定義的標籤,但是需要實現解析自定義標籤的介面;

        3.配置檔案中可能包含bean例項、事務宣告、系統環境資料等資料,將檔案讀取成功之後,就需要將其填裝在容器中,供初始化並使用。

二、載入例項

        根據配置配置,載入容器中的bean例項過程:

       1.轉換對應的beanName。bean標籤中的name可能是別名,或者是FactoryBean的修飾符,這一步是解析配置,獲取最終beanName。一般情況下,spring通過反射機制利用bean的class屬性制定實現類來例項化bean,但也允許class屬性的類是實現FactoryBean介面的,完成自定義的例項化(spring通過反射發現class屬性指定的類實現了FactoryBean介面,會呼叫其getObject()方法獲得例項)。

        2.嘗試從快取中載入該bean的單例項,在bean真正建立完成前會在快取中宣告一個獲取bean例項的ObjectFactory(類似先佔位,建立成功後再更換其內容),主要用於迴圈依賴檢測。

        3.bean例項化,到這裡已經獲取了原始狀態的bean物件,需要判斷是否是FactoryBean,如果不是則直接返回這個bean物件,如果是factoryBean且需要的直接就是factoryBean物件而不是factoryBean#getObject()物件,也直接返回bean物件;否則需要再次通過factoryBean#getObject()返回物件;

Spring獲取bean的規則之一:儘可能保證所有bean初始化後都會呼叫註冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理。這樣可以針對此次特性設計自己的業務邏輯。

        4.原型模式的依賴檢查,如果是單例項,則需要檢查是否存在迴圈依賴;

        5.檢測parentBeanFactory;

        6.將儲存XML配置檔案的GernericBeanDefinition轉換為RootBeanDefinition,因為所有的Bean後續處理都是針對於RootBeanDefinition的;

        7.尋找依賴,判斷是否依賴其他bean,是否依賴使用其他屬性資料,如果依賴,則需要首先載入被依賴的例項或資料;

        8.針對不同的scope進行bean建立;

        9.型別轉換,可能存在返回的例項型別和requireType不一樣,這時需要轉換成requireType指定的型別。

bean的建立過程:

    1)如果是單例需要首先清除快取:

    2)例項化bean, a.如果存在工程方法就使用工程方法進行初始化;b.如果有多個建構函式,使用引數匹配製定建構函式;c.否則使用預設建構函式初始化;

    3)bean組裝處理,比如註解注入等;

    4)依賴處理;

    5)屬性填充,將屬性填充進bean例項中;

    6)迴圈依賴檢查,檢測已載入的bean是否已經出現了依賴迴圈,如出現則拋異常;

    7)註冊DisposableBean,配置了destroy-method,則會在銷燬時呼叫;

bean例項的載入方式有哪些?

針對不同迴圈依賴,spring是怎麼做的?

附XmlBeanFactory類圖:

  

三、容器功能擴充套件-ApplicationContext

        ClassPathXmlAppplicationContext 裝載xml配置檔案,並返回ApplicationContext容器。
        步驟:
            A.繼承自AbstractApplicationContext類中的prepareRefresh()方法,初始化前的準備工作,如初始化所需的系統引數校驗載入等;
            B.obtainFreshBeanFactory()方法,載入XML檔案,初始化BeanFactory。
            C.prepareBeanFactory()方法對BeanFactory做封裝,擴充套件處理,比如註解處理等。
            D.postProcessBeanFactory()方法,允許對已完成標準初始化的bean,通過繼承的方式進行業務層的擴充套件處理。
            E.invokeBeanFactoryPostProcessors()方法,啟用所有型別的beanFactory;
            F.registerBeanPostProcessors()註冊攔截bean建立的bean處理器。
            G.initMessageSource()初始化Message源,即對不同語言的訊息體進行國際化處理。
            H.initApplicationEventMulticaster()初始化應用事件廣播。
            I.onRefresh()子類初始化特殊的bean。
            J.registerListeners()找出所有的listener beans ,註冊到到訊息廣播器中。
            K.finishBeanFactoryInitialization()初始化剩下的非惰性的單例項。

            L.finishRefresh()完成重新整理過程,併發出通知

附ClassPathXmlApplicationContext類圖:


      參考書籍:《spring原始碼深度解析》