1. 程式人生 > >Spring原始碼學習之容器的功能擴充套件

Spring原始碼學習之容器的功能擴充套件

我們都站在巨人的肩膀上

宣告:參考《Spring原始碼深度解析》

ApplicationContext和BeanFactory區別:

Application提供了更多的擴充套件功能,簡單來說,就是:Application包含了BeanFactory的所有功能。

1.Application和BeanFactory載入方式

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
Application bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml"
);

2.設定配置路徑

public void setConfigLocations(String[] locations){
    if(locations!=null){
        ...
        //解析指定路徑
        this.configLocations[i] = resolvePath(location[i]).trim();
        ...
    }
}

此函式主要用於解析給定路徑陣列,如果包含特殊符號(如:${var}),則在resolvePath中會搜尋匹配的系統變數並替換。

3.在refresh函式中幾乎包含了Application中提供的全部功能:

public void refresh() throws BeansException,IlleGalStateException{
    synchronized(this.startupShutdownMonitor){
        //準備重新整理的上下文
        prepareRefresh();
        //初始化BeanFactory,進行xml讀取
        ConfigurableListTableBeanFactory beanFactory = obtainFreshBeanFactory();
        //對BeanFactory進行各種功能填充
prepareBeanFactory(beanFactory); tyr{ //子類覆蓋方法做額外的處理 postProcessBeanFactory(beanFactory); //啟用各種BeanFactory處理器 invokeBeanFactoryPostProcessors(beanFactory); //註冊攔截Bean建立的Bean處理器,這裡只是註冊,真正的呼叫是在getBean時候 registerBeanPostProcessors(beanFactory); //為了上下文初始化Message源,即不同語言的訊息體,國際化處理 initMessageSoure(); //初始化應用訊息廣播器,並放入“applicationEventMulticaster”bean中 initApplicationEventMulticaster(); //留給子類初始化其他的bean onRefresh(); //在所有註冊的備案中查詢listener bean,註冊到訊息廣播中 registerListeners(); //初始化剩下的單例項(非惰性) finishBeanFactoryInitialization(beanFactory); //完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreachEvent通知別人 finishRefresh(); }catch(BeanException ex){ destroyBeans(); cancelRefresh(ex); throw ex; } } }

簡單概括一下步驟:
1. 初始化前的準備工作,比如對系統屬性或者環境變數進行準備及驗證。
2. 初始化BeanFactory,並進行XML檔案讀取。
3. 對BeanFactory進行各種功能填充。(例如:@Autowired 等註解就是這一步完成)
4. 子類覆蓋方法做額外處理。這一步很少用到,書上解釋說的是,Spring優秀的開放式架構,方便程式猿在業務需求上進行進一步擴充套件已存在的功能。
5. 啟用各種BeanFactory處理器。
6. 註冊攔截bean建立的bean處理器,並不是真正的呼叫,呼叫是在getBean的時候。
7. 為上下文初始化Message源,對不同語言的訊息體進行國際化處理。
8. 初始化應用訊息廣播器,並放入“applicationEventMulticaster”bean中
9. 留給子類來初始化其他bean
10. 在所有註冊的bean中查詢listener bean,註冊到訊息廣播中。
11. 初始化剩下的單例項。
12. 完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreachEvent通知別人

4.容器擴充套件部分介紹

這裡我們只介紹部分功能的一些處理,具體細節還請參考原書籍

1.載入BeanFactory

Spring中obtainFreshBeanFactory方法實現了BeanFactory的全部功能並且添加了大量擴充套件。經過這個函式知乎ApplicationContext就具有了BeanFactory的全部功能。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory(){
    //初始化BeanFactory,並進行XMl檔案讀取,並將得到的BeanFactory記錄在當前實體的屬性中
    refreshBeanFactory();
    //返回當前實體的beanFactory屬性
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    ...
    return beanFactory ;
}

//具體實現方法交給這個方法
protected final void refreshBeanFactory() throws BeansException{
    ...
    try{
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        //為了序列化指定id,如果需要的話,讓這個BeanFactory從id反序列化到BeanFactory物件
        beanFactory.setSerializationId(getId());
        //定製beanFactory,設定相關屬性,包括是否允許覆蓋同名稱的不同定義的物件以及迴圈依賴以及設定@Autowried和@Qualifier註解直譯器QualifierAnnotationAutowrieCandidateResolver
        customizeBeanFactory(beanFactory);
        //初始化DodumentReader,並進行XML檔案讀取及解析
        LoadBeanDefinitions(beanFactory);
        synchronized(this.beanFactoryMonitor){
            this.beanFactory = beanFactory;
        }
    }catch(IOException ex){
        ...
    }
}

步驟解析:
1. 建立DefaultListableBeanFactory 。DefaultListableBeanFactory 是容器的基礎,必須要首先例項化。
2. 指定序列化ID。
3. 定製BeanFactory。
4. 載入BeanDefinition。
5. 使全域性變數記錄BeanFactory類例項。因為DefaultListableBeanFactory 型別的遍歷beanFactory是函式內的區域性變數,所以要使用全域性變數記錄分析結果。

2.定製BeanFactory

在基本容器的基礎上,增加了是否允許覆蓋是否允許誇張的設定並提供了註解@Qualifier和@Autowired的支援。
在原始碼中是否允許覆蓋和依賴只是判斷了是否為空,如果不為空要進行設定,那麼就使用子類覆蓋方法。

public class ... entends ClassPathXmlApplicationContext{
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory){
        //是否允許覆蓋通名稱的不同定義物件
        super.setAllowBeanDefinitionOverriding(false);
        //是否允許bean之間存在迴圈依賴
        super.setAllowCirularRefernces(false);
        super.customizeBeanFactory(beanFactory);
    }
}

3.註冊監聽器

protected void registerListeners(){
    //硬編碼方式註冊的監聽器
    for(ApplicationListener<?> listener:getApplicationListeners()){
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    //配置檔案註冊的監聽器處理
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class,true,false);
    for(String lisName : listenerBeanNames){
        getApplicationEventmulticaster().addApplicationlistenerBean(lisName);
    }
}

4.finishRefresh
在Spring中還提供Lifecycle介面,Lifecycle中包含start/stop方法,實現此介面後Spring會保證在啟動的時候呼叫start方法開始生命週期,並在Spring關閉的時候呼叫stop方法結束生命週期,通常用來配置後臺程式猿,在啟動後一直執行(入隊MQ輪詢等)。而ApplicationContext的初始化最後證實保證了這一功能的實現。

protected void finishRefresh(){
    initlifecycleProcessor();
    getLifecycleProcessor().onRefresh();
    publishEvent(new ContextRefreshedEvent(this));
}
  1. initLifecycleProcessor。當ApplicationContext啟動或者停止的時候,會通過LifecycleProcessor來生命與所有生命的bean的週期做狀態更新,而在LifecycleProcessor試用期首先需要初始化。
  2. onRefresh。啟動所有實現了Lifecycle介面的bean。
  3. publicEvent。當完成ApplicationContext初始化的時候,要通過Spring中的時間釋出機制發出ContextRefreshedEvent事件,以保證對應的監聽器可以做到進一步的邏輯處理。