Spring探祕2.1:容器啓動中的refresh方法

    在前一篇文章Spring探祕2:ApplicationContext啓動流程中提到了Spring容器啓動的最後一步是refresh,即配置的刷新,這是容器啓動過程中一個核心的步驟,實現了啓動容器的主要的功能。本文會簡單介紹一下AbstractApplicationContext#refresh()方法的流程,其中涉及到的比較複雜的過程還需要另外詳細分析。首先其源碼如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 讓容器準備好刷新。
        prepareRefresh();

        // 通知子類刷新其內部的Bean工廠
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 爲容器準備好Bean工廠
        prepareBeanFactory(beanFactory);

        try {
            // 目前是一個空方法
            postProcessBeanFactory(beanFactory);

            // 調用容器中已註冊爲Bean的所有BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // 註冊所有的BeanPostProcessor(攔截Bean創建過程)
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

prepareRefresh()

  • 讓容器準備好刷新,設置啓動時間和活動標識
  • 初始化property源,驗證環境中的property是否合法(即判斷其可解析)

obtainFreshBeanFactory()

    該方法是用於從子類中獲取實際的Bean工廠對象。

  • 先調用refreshBeanFactory()通知子類刷新Bean工廠
    • 在GenericApplicationContext#refreshBeanFactory()中用了一個CAS操作將容器的refreshed屬性置爲true
  • 再調用抽象方法getBeanFactory()獲取Bean工廠,這個抽象方法就是留給子類實現的工廠方法

因此這裏就是一個工廠模式的實例

prepareBeanFactory()

    該方法是在獲取到了容器中的Bean工廠後,配置其中的一些工具與屬性。

  • 設置類加載器
  • 設置Bean表達式解析器,bean初始化完成後填充屬性時會用到
  • 添加一個PropertyEditorRegistrar,屬性編輯器註冊器,用於將屬性編輯器(PropertyEditor)註冊到容器中
  • 添加一個BeanPostProcessor (ApplicationContextAwareProcessor),其功能是爲各種實現了Aware接口的bean注入其需要的容器中的信息
  • 設置各種Aware實現類爲忽略自動裝配
  • 設置自動裝配的類及自動裝配的對象
  • 根據需要添加動態織入的功能
  • 註冊各種默認的環境bean(Environment, SystemProperty, SystemEnvironment)

postProcessBeanFactory()

    該方法在框架中是一個空方法,是預留給子類去實現的,用於在Bean工廠準備好後的一些處理工作。

invokeBeanFactoryPostProcessors()

    該方法是刷新過程中最核心的一個方法,調用了容器中的BeanFactoryPostProcessor(即Bean工廠後置處理器),這是Spring框架向外暴露的一個擴展點,開發者可以通過實現該接口來對Bean工廠進行一些增強。這個方法的流程簡單來說是這樣:

  • 先找到容器中所有的BeanDefinitionRegistryPostProcessor接口(它是BeanFactoryPostProcessor的子接口)的實現類,按順序調用其postProcessBeanDefinitionRegistry()方法
  • 再調用這些BeanDefinitionRegistryPostProcessor的postProcessBeanFacory()方法
  • 最後再調用普通的BeanFactoryPostProcessor的postProcessBeanFactory()方法

具體的流程還需要單獨再進行分析。

    在默認情況下,此時容器中只有一個ConfigurationClassPostProcessor,它實現了BeanDefinitionRegistryPostProcessor接口。顧名思義該類的功能是在Bean工廠準備好後,處理容器中處理配置類。它的兩個主要功能如下:

  • postProcessBeanDefinitionRegistry()方法:找到所有的配置類,並解析這些配置類(這裏所說的配置類是廣義上的配置類,只要有相關的配置註解的類都會被解析)。主要處理了以下的註解:
    • @PropertySource
    • @ComponentScan:掃描了該註解指定的包,並將包內所有@Component註解的類都生成BeanDefinition並註冊到容器中
    • @Import: 根據Import註解傳入的類不同(ImportSelector, ImportBeanDefinitionRegistar, 其他)有不同的處理流程,處理結束後該註解引入的類的BeanDefinition應該已經註冊到容器中了
    • @ImportResource
    • 配置類中的@Bean方法
    • 接口中的默認方法
    • 如果配置類有父類,還要處理其父類
  • postProcessBeanFactory()方法:對於有@Configuration註解的配置類的BeanDefinition,會將他們替換爲CGLib增強的子類。

這裏要爲什麼要做CGLib代理?看了一些源碼可知道,最根本的原因是爲了增強配置類中的@Bean方法,使得即使多次調用這些方法也能夠得到同一個Bean對象,實現Bean的單例模式。

ConfigurationClassPostProcessor是Spring框架中最重要的一個後置處理器,實現以上功能的原理以及具體的流程也需要單獨分析。

registerBeanPostProcessor()

    會將所有實現了BeanPostProcessor接口的Bean註冊到容器中

initMessageSource()

    在容器中初始化消息源

initApplicationEventMulticaster()

    初始化事件廣播器

onRefresh()

    空方法,也是爲子類預留的,令子類能夠通過重寫該方法來初始化一些特殊的Bean。

registerListeners()

    將實現了ApplicationListener接口的Bean註冊到容器中作爲監聽器

finishBeanFactoryInitialization()

    完成Bean工廠的初始化,生成所有單例Bean。即實例化Bean就是主要在該方法中進行的。

finishRefresh():

    完成容器的刷新過程

  • 初始化容器的生命週期處理器並通知其容器正在刷新
  • 發佈容器刷新完成的事件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章