Bean的一生(Bean的生命週期)

RosaDarker發表於2019-01-11

1. 什麼是Bean?

Bean是spring中組成應用程式的主體由spring IoC容器所管理的物件(IoC容器初始化、裝配及管理的物件)。如果把spring比作一座大型工廠,那麼bean就是該工廠的產品。

題外話:bean這個單詞翻譯成中文有很多意思,豆子、嘴峰、毫無價值的東西…而事實上它是spring的核心,價值非凡。這個命名可能來自於開發者的一點惡趣味。如果留心,生活處處是驚喜,你可以在程式設計中獲得不少樂趣。比如:Git翻譯過來有“飯桶、無用的人”的意思,redis的埠6379來自於MERZ(長期以來被開發者antirez及其朋友當作愚蠢的代名詞)…

2. 在瞭解Bean的一生前,你需要了解一些東西

2.1 spring容器

  • 容器是spring框架實現的核心,負責了物件整個生命週期的管理(建立,裝配,銷燬)。
  • 容器是核心,而容器不唯一(spring容器 ∈ IoC容器)。並不是說只有Spring的容器才叫IOC容器,基於IOC容器的框架還有很多,並不是Spring特有的。框架本身就提供了很多個容器的實現。大概分為兩種型別:一種是不常用的BeanFactory,這是最簡單的容器,只能提供基本的DI功能;還有一種就是繼承了BeanFactory後派生而來的應用上下文。

2.2 應用上下文ApplicationContexts

應用上下文是spring容器抽象的一種實現,一種容器物件。

  • 其抽象介面ApplicationContext的本質:一個維護Bean定義以及物件之間協作關係的高階介面。

    比起BeanFactory,它能提供更多企業級的服務,例如解析配置文字資訊等等,這也是應用上下文例項物件最常見的應用場景。有了上下文物件,我們就能向容器註冊需要Spring管理的物件了。對於上下文抽象介面,Spring也為我們提供了多種型別的容器實現,供我們在不同的應用場景選擇。詳情請看:Spring基礎篇——Spring容器和應用上下文理解

2.3 Aware

spring DI最大的亮點是所有bean對spring容器的存在是沒有意識的(即可替換容器,此時bean間耦合度很低),但實際開發中很有可能要用到spring本身的功能資源,這時候bean需要意識到spring容器的存在,才能呼叫spring所提供的資源。spring Aware中的介面可以讓我們可獲取spring的資源。

2.4 後置處理器BeanPostProcessor

此介面允許自定義修改新bean的一個例項,讓我們可以在spring容器完成bean例項化、配置以及其他初始化方法前後新增一些自己的邏輯處理。含有兩個方法,介面宣告如下:

public interface BeanPostProcessor {
    //bean初始化方法呼叫前被呼叫
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法呼叫後被呼叫
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

2.5 Bean的自定義初始化和銷燬方法(證明程式碼)

如果要在bean初始化後銷燬前需要執行特定的操作:

  • 使用註解,在指定的方法前加@PostConstruct / @PreDestory註解來指定該方法在初始化之後還是銷燬之前呼叫;
  • 在xml配置bean時指定init-method / destroy-method屬性指定初始化後/銷燬之前呼叫的操作方法;
  • 實現InitializingBean / DisposableBean介面來定製初始化之後/銷燬之前的操作方法
    InitializingBean:執行afterPropertiesSet()在所有bean屬性被設定後
    DisposableBean:執行destory()在spring容器釋放該bean之後

他們的執行順序如下:
Bean在例項化時:Constructor → @PostConstruct → InitializingBean → init-method
Bean在銷燬的過程中:@PreDestroy → DisposableBean → destroy-method

3. Bean建立物件過程

  1. 建立物件例項

    Object o = new Object();

  2. 依賴注入

    o.setXxx(…)

  3. spring bean擴充套件方法

    init-method, BeanPostProcessor, xxxAware等

4. Bean例項化的三種方式 詳情

  • 構造器例項化
    spring容器通過bean對應的預設的建構函式來例項化bean。

  • 靜態工廠方式例項化
    首先建立一個靜態工廠類,在類中定義一個靜態方法建立例項。

  • 例項工廠方式例項化
    該種方式的工廠類中,不再使用靜態方法建立Bean例項,而是採用直接建立Bean例項的方式。同時在配置檔案中,需要例項化的Bean也不是通過class屬性直接指向其例項化的類,而是通過factory-bean屬性配置一個例項工廠,然後使用factory-method屬性確定使用工廠中哪個方法。

5. Bean例項生命週期的執行過程

  1. 初始化spring容器(其實是第0步,bean生命週期不包括,但卻是bean所必須的,也許可以看作產房?);
  2. spring對bean例項化,預設是單例(Bean的作用域);
  3. 檢查Aware相關介面並設定相關依賴:
    1. 如果實現了BeanNameAware介面,spring將bean的id傳給setBeanName()方法;
    2. 如果實現了BeanFactoryAware介面,spring呼叫setBeanFactory()方法,將BeanFactory例項傳進來;
    3. 如果實現了ApplicationContextAware介面,spring呼叫setApplicationContext()會被呼叫,將應用上下文的應用傳入到Bean中
  4. BeanPostProcessor前置處理(如果有),呼叫postProcessBeforeInitialization()
  5. 初始化相關:如果實現了InitializingBean介面,spring呼叫afterPropertiesSet();類似地,如果實現了init-method屬性宣告瞭初始化方法,該方法也會被呼叫;亦或是@PostConstruct註解
  6. BeanPostProcessor後置處理(如果有),呼叫postProcessorAfterInitialization()
  7. 註冊必要的Destruction相關回撥介面
  8. 此時bean已經準備就緒,可被程式使用了,將一直駐留在應用上下文中,直到該應用上下文被銷燬
  9. 銷燬相關: 如果實現了DisposableBean介面,spring呼叫destory();類似地,還有自定義銷燬方法destory-method和註解@PreDestroy

相關文章