Spring探祕2:ApplicationContext啓動流程

     ApplicationContext是Spring框架中最基礎的接口之一,可以認爲其實現類就是一個Spring的環境(容器),而一個簡單的Spring應用的啓動過程就是一個ApplicationContext的實現類的實例化過程,是研究Spring源碼的很好的切入點。這裏研究的實現類是AnnotationConfigApplicationContext,運行的代碼爲前文Spring探祕0:源碼構建中的測試代碼,啓動類的代碼如下:

public class DemoApp {
  public static void main(String[] args) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        DemoComponent component = context.getBean(DemoComponent.class);
        component.foo();

    }
}

要區分的一個概念就是“容器”,本文中提到的容器都是指Spring框架的容器,即管理Service,Dao以及Component這些Bean的一個“環境”。與SpingMVC的容器不同,SpringMVC的容器是管理Controller的環境。與Tomcat這些Web容器就更不一樣了。

相關的類與接口

繼承結構

     AnnotationConfigApplicationContext這個類從類名就可以看出,它是一個通過註解來配置的Spring容器,實例化該容器時,可以傳入一個配置類,上面代碼中的AppConfig就是我自定義的一個配置類,其中唯一的配置項就是通過@ComponentScan註解配置了掃描的包。
    AnnotationConfigApplicationContext這個類的繼承結構如下圖(圖中只包含了與啓動容器關係較大的類和接口,實際的繼承層次要複雜得多):

applicationcontext

從中可以看出

  1. ApplicationContext最終還是要實現BeanFactory,而這個父接口的含義可以參考前一篇文章。因此可以說ApplicationContextBeanFactory功能上的增強。
  2. AnnotationConfigApplicationContext的直接父類GenericApplicationContext其實還有其他的一些子類,如GenericXmlApplicationContext等,分別用於表示不同配置方式的容器。

啓動容器時涉及到的類

     容器的啓動過程就是一個ApplicationContext的實例化過程,本文研究的容器實現類爲AnnotationConfigApplicationContext,啓動的過程中會涉及到許多其他的類,包括容器中的實例對象的實例化,向容器中註冊的一些初始的處理器等。這裏通過類圖的形式總結了部分類以及這些類之間的關係。

startclass

各類的簡介

自頂向下地簡單介紹相關的類:

  • BeanDefinition: 用於描述一個Bean實例的信息;根據Bean的來源不同有具體的實現類,如AnnotatedGenericBeanDefinitionRootBeanDefinitionScannedGenericBeanDefinition等。
  • AbstractApplicationContext: 是ApplicationContetxt接口的抽象實現類,該類沒有指定容器的配置類型,只實現了容器的一些通用功能,這些功能增強了簡單的BeanFactory。與簡單的BeanFactory相比,ApplicationContext應該能夠主動探測到容器內的一些特殊的bean。因此該類自動註冊了一些BeanFactoryPostProcessorBeanPostProcessorApplicationListener,在一些特殊的時期能夠自動調用這些對象的功能。
  • BeanFactoryPostProcessor: 這就是一種ApplicationContext能夠主動調用的特殊的Bean,從類名不難猜到,實現了該接口的Bean會在Bean工廠初始化完成後被調用(稱爲後置處理器)。因此我們可以通過實現該接口來插手Bean工廠初始化過程,從而擴展Spring的功能。值得注意的是,該接口的實現類只能去處理、修改bean definitions,而不應該對Bean實例作任何處理,因爲調用時,bean都還沒實例化。
  • BeanDefinitionRegistryPostProcessor,它是BeanFactoryPostProcessor的子接口,即除了實現BeanFactoryPostProcessor的功能之外,還能夠實現動態地向容器中添加BeanDefinition的功能。該功能會在一般的BeanFactoryPostProcessor之前被調用。
  • PostProcessorRegistrationDelegateAbstractApplicationContext將調用後置處理器的功能委派給該類,應該只是爲了減少每個類的代碼量?
  • BeanDefinitionRegistry:registry意爲“註冊處”,所以這個接口也就是表示BeanDefinition註冊的地方,一般都是由Bean工廠實現,用於管理BeanDefinition,包括註冊、移除、獲取等。對BeanDefinition有管理需要的地方就可以調用該接口的方法。
  • GenericApplicationContext: 是AbstractApplicationContext的子類,主要維護了一個DefaultListableBeanFactory實例,通過該實例實現了BeanFactory接口(裝飾者模式)。另外也實現了BeanDefinitionRegistry接口,給有需要的類註冊BeanDefinition
  • DefaultListableBeanFactory:這就是Spring內BeanFactory接口和BeanDefinitionRegistry的一個默認實現。
  • AnnotationConfigApplicationContext: 是GenericApplicationContext的子類,是一個獨立的應用上下文(容器),構造時可以接收多個組件類作爲參數(一般是配置類)。
  • ClassPathBeanDefinitionScanner: 是AnnotationConfigApplicationContext中一個重要的工具,用於掃描classpath上所有的Bean,並將相應的BeanDefifnition註冊到給定的BeanDefinitionRegistry中。(一般registry就是一個BeanFactory或者是ApplicationContext,即當前的Spring容器)
  • AnnotatedBeanDefinitionReader:是AnnotationConfigApplicationContext中另一個重要的工具,也是用於接收一個Bean類,轉換爲BeanDefifnition並將其註冊到registry中,但是不同點在於它只用於讀取顯式註冊的類,即與ClassPathBeanDefinitionScanner相比沒有掃描classpath的功能。

啓動流程原理分析

     AnnotationConfigApplicationContext的構造方法的調用層次如下圖所示:

constructor

構造父類GenericApplicationContext

  • 再遞歸地構造父類AbstractApplicationContext,該父類中的BeanFactoryPostProcessor的list就是在此時實例化的
  • 實例化beanFactory屬性爲DefaultListableBeanFactory。

工廠模式:AbstractApplicationContext類定義了一個抽象方法getBeanFactory(),通過該方法實現了BeanFactory接口。該方法就是需要子類去實現的工廠方法,不同的子類可能有不同的BeanFactory實現。

實例化reader屬性

  • 設置reader中的registry,conditionEvaluator屬性

  • 調用 AnnotationConfigUtils.registerAnnotationConfigProcessors() 向容器註冊一些後置處理器的BeanDefinition(並且其實現類均爲RootBeanDefinition),包括:

    • ConfigurationClassPostProcessor:是一個BeanDefinitionRegistryPostProcessor實現類,用於處理配置類
    • AutowiredAnnotationBeanPostProcessor:用於處理自動注入的類
    • CommonAnnotationBeanPostProcessor:支持JSR-250的註解
    • PersistenceAnnotationBeanPostProcessor:支持JPA的註解
    • EventListenerMethodProcessor
    • DefaultEventListenerFactory
  • 此時,reader的實例化已經完成,程序運行到這裏(指AnnotatedBeanDefinitionReader構造方法的最後一行)時,Bean工廠中應該已經存在一些BeanDefinition

bdmap1

實例化scanner屬性

  • 該實例化過程比較簡單,只是在scanner的掃描過濾器中添加了@Component這個註解。

註冊構造方法的參數傳入的組件類

  • 調用reader.register(),追蹤調用,最終的邏輯是在doRegisterBean()方法實現的

刷新 refresh()

  • 刷新容器是容器啓動的最重要的一個階段,有很多的工作包括準備Bean工廠、調用BeanFactoryPostProcessors、註冊BeanPostProcessors等等,需要另外進行詳細的分析。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章