spring-IOC容器源碼分析(一)bean初始化流程

在傳統的開發步驟中,若是一個類依賴於另外一個類的實例才能完成任務的話,都須要開發者手動new一個實例。以後手動設置到任務類中。但spring的出現,爲咱們提供了一種稱爲「依賴注入」(Dependency Inject)的機制。bean的實例化在spring container內部完成,開發者只須要從xml或java code來配置bean達到定製實例化bean。並且,可讓咱們經過註解的方式,爲咱們自動注入須要的依賴。
這樣,開發者只須要遵循面向接口來開發應用,把實例化具體類和注入依賴的步驟抽離出業務代碼,達到解耦的要求。若是哪天須要使用其餘的接口實現依賴,只須要將新的實現配置進spring container。其餘業務代碼無需更改。這篇文章將圍繞着spring是如何實現bean的實例化、如何實現依賴注入來展開,剖析其內部運行機制java

測試用例

// 定義一個簡單的bean
public class Car {
    public String color;
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}

// 定義一個配置類,向Spring bean container註冊bean
@Configuration
public class Config {
    @Bean
    public Car car() {
        Car car = new Car();
        car.setColor("red");
        return car;
    }
}

// 編寫一個測試類來初始化spring bean container,再從其中獲取咱們在Config類中定義的bean的實例
public class ContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        Car car = context.getBean(Car.class);
        System.out.println(car.getColor());
    }
}
複製代碼

運行這個用例,spring bean container將在其內部對咱們注入的bean進行實例化、初始化兩個步驟。因爲這裏沒有定義bean的做用域,所以咱們註冊的這個bean(即Car)將以單例的形式存在於container中。每一次調用context.getBean(Car.class)返回的都是同一個Car的實例。spring

源碼分析

說明:如下的流程分析,只圍繞spring容器實例化singleton bean(即單例)的主流程進行數據庫

主流程

對於spring這樣一個比較複雜的框架,其中包含了各類繁雜的業務邏輯。若是一開始就直接深究到每個細節,咱們沒法對spring container有一個比較全局的觀感,所以在這裏先把整個主流程畫出來,創建一個全局的藍圖。 app

解析註冊BeanDefinition

註冊和解析BeanDefinition,發生在AnnotationConfigApplicationContext#register流程中,其方法內部使用了AnnotatedBeanDefinitionReader#register來實現BeanDefinition的解析和註冊;並且在實例化AnnotatedBeanDefinitionReader後,當即向container註冊了多個BeanPostProcessor的BeanDefinition(應用於bean的實例化過程)框架

準備BeanFactory

在AnnotationConfigApplicationContext內部,組合了DefaultListableBeanFactory。在prepareBeanFactory(beanFactory)方法的調用過程當中,向beanfactory注入了環境變量、環境屬性等。並且注入了多個BeanPostProcessor。源碼分析

調用BeanFactoryPostProcessor

到了這一步,此時的container已經註冊了一系列的BeanFactoryPostProcessor、BeanPostProcessor和應用層相關的bean的BeanDefinition(如當前測試用例的Car)。因爲此時全部的bean(包括BeanFactoryPostProcessor、BeanPostProcessor已經應用層的bean)都是以BeanDefinition存在於container中,並未實例化。這就提供了一個機會,添加特定的BeanFactoryPostProcessor,讓spring在實例化bean以前,能夠定製修改BeanDefinition中的一些數據(如經常使用的PropertyPlaceholderConfigurer,從外部properties文件讀取配置,定義bean的屬性);
默認狀況下,只調用了ConfigurationClassPostProcessor,做用:post

  1. 解析配置類,將其定義的bean注入到beanfactory
  2. 利用ConfigurationClassEnhancer加強了配置類的功能
  3. 註冊BeanPostProcessor:ImportAwareBeanPostProcessor
註冊BeanPostProcessor

繼續上一步流程,處理完BeanDefinition以後,對前面流程中註冊到beanfactory中的BeanPostProcessor進行實例化,並添加到beanfactory中的BeanPostProcessor處理隊列中。通過這一步以後,beanfactory中的BeanPostProcessor隊列存在如下BeanPostProcessor:測試

  1. ApplicationContextAwareProcessor
  2. ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
  3. PostProcessorRegistrationDelegate$BeanPostProcessorChecker
  4. CommonAnnotationBeanPostProcessor
  5. AutowiredAnnotationBeanPostProcessor
  6. RequiredAnnotationBeanPostProcessor
  7. ApplicationListenerDetector
真正實例化和初始化bean的流程

這個步驟是經過調用DefaultListableBeanFactory#preInstantiateSingletons()方法完成的。實現了預加載全部已註冊的bean,這也是ApplicationContext與BeanFactory實現類的區別,在BeanFactory實現類中,只有對一個bean調用getBean(beanname)方法以後纔會進行bean的加載。而ApplicationContext則是直接觸發其內部的BeanFactory加載全部定義好的bean。
在加載bean的過程當中,涉及到三個步驟:ui

  1. 實例化
  2. 填充屬性
  3. 初始化

實例化並初始化bean流程

主流程

實例化

經過調用AbstractAutowireCapableBeanFactory#createBeanInstance來實例化bean(在這以前,spring提供了一個機會能夠經過BeanPostProcessor來建立bean,而不是常規的bean實例化,跟AOP相關)。
實例化後,調用了MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,涉及到的實現類有:this

  1. CommonAnnotationBeanPostProcessor,解析類準備@Resource注入須要的InjectionMetadata
  2. AutowiredAnnotationBeanPostProcessor,解析類準備@Autowired注入須要的InjectionMetadata
  3. RequiredAnnotationBeanPostProcessor,空實現
  4. ApplicationListenerDetector,標記了該bean是否爲單例
填充bean屬性

實例化bean以後,就須要爲bean填充bean的屬性值了。這一步主要是經過調用:InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation: 能夠直接對bean填充屬性,以後直接返回。忽略後續的全部填充行爲。默認沒有進行這一步流程,而是不作任何處理,進入下一個流程

  1. ImportAwareBeanPostProcessor
  2. CommonAnnotationBeanPostProcessor
  3. AutowiredAnnotationBeanPostProcessor
  4. RequiredAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor#postProcessPropertyValues: 各類自動注入的解析,如@Resource、@Autowired等
  5. ImportAwareBeanPostProcessor
  6. CommonAnnotationBeanPostProcessor
  7. AutowiredAnnotationBeanPostProcessor
  8. RequiredAnnotationBeanPostProcessor 最後經過applyPropertyValues()進行bean的賦值
初始化

進行到這一步時,bean已經從BeanDefinition實例化爲了bean的實例,而且填充了屬性。是時候進行一下從外部而來的初始化邏輯了(非BeanDefinition相關的)。主要是:

  1. Aware接口的注入
  2. BeanPostProcessor#postProcessBeforeInitialization處理
  3. InitializingBean#afterPropertiesSet實現類的初始化方法
  4. BeanPostProcessor#postProcessAfterInitialization處理
  5. 註冊DisposableBean#destroy,在關閉容器時銷燬bean的回調操做

總結

以上咱們梳理了spring container加載bean的主體流程,spring爲咱們提供了幾大擴展點:

  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. Aware接口實現
  4. InitializingBean#afterPropertiesSet
  5. DisposableBean#destroy 爲咱們提供了改造bean的契機,方便在實際開發過程當中定製化bean的加載。常見的有:
  6. PropertyPlaceholderConfigurer做爲BeanFactoryPostProcessor的間接實現類,在bean的加載過程當中,讀取外部properties文件,對已註冊的BeanDefinition進行修改,達到了從外部文件配置bean的目的;
  7. 在數據庫鏈接池的bean定義上,咱們都會用@PreDestroy指定一個銷燬的回調來釋放數據庫鏈接資源
相關文章
相關標籤/搜索