Spring Bean 生命週期之「我從哪裏來?」 懂得這個很重要

Spring bean 的生命週期很容易理解。實例化 bean 時,可能須要執行一些初始化以使其進入可用 (Ready for Use)狀態。相似地,當再也不須要 bean 並將其從容器中移除時,可能須要進行一些清理,這就是它的生命週期java

frog-758072_1920.png

上一篇文章 面試還不知道BeanFactory和ApplicationContext的區別? 中說明了接口 Beanfactory 和 Applicationcontext 能夠經過 T getBean(String name, Class<T> requiredType) 方法從 Spring 容器中獲取bean,區別是,前者是懶加載形式,後者是預加載的形式。那麼問題來了:面試

這些 Spring Beans 是怎麼生成出來的呢?spring

在正式回答這個問題以前,先解答一些有關 Java Bean, Spring Bean 和 Spring IoC 容器這些概念性的疑惑,我但願經過下面這個例子形象說明這些問題:編程

小學生 (Java Bean)經過提交資料申請(元數據配置)加入了少先隊(Spring Ioc 容器),學習了一些精神與規定以後,變成了少先隊員(Spring Bean)設計模式

從這裏能夠看出,Java Bean 和 Spring Bean 都是具備特定功能的對象,小學生仍是那個小學生,只不過加入了少先隊以後有了新的身份,新的身份要按照組織 (Spring Ioc)的規定履行特定義務網絡

來看下圖加深一下了解 框架

Xnip2019-07-01_20-14-05.jpg

首先要有容器,實例化 Spring Ioc 容器是很是簡單的,接口 org.springframework.context.ApplicationContext 表示Spring IoC容器,負責實例化,配置和組裝上述 bean。 容器經過讀取配置元數據獲取有關要實例化,配置和組裝的對象的指令。 配置元數據一般以XML,Java 註解或代碼的形式表示。 它容許你本身表達組成應用程序的對象以及這些對象之間豐富的相互依賴性,好比這樣:ide

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring.xml", "spring1.xml"});
複製代碼

有了容器,咱們須要作哪些處理,使其內部對象變爲 Ready for Use 的狀態?
咱們須要經過 Spring 容器實例化它們,Spring 爲咱們提供了三種方式:post

三種初始化方式

InitializingBean

Spring 爲咱們提供了 InitializingBean 接口學習

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
複製代碼

咱們能夠經過實現 InitializingBean 接口,在其惟一方法 afterPropertiesSet 內完成實例化的工做,可是 Spring Framework 官方並不建議咱們經過這種方法來完成 Bean 的實例化,這是一種強耦合的方式,咱們看到框架層面纔會用到這個方法。

@PostConstruct

這種方式是 Spring 很是提倡的一種方式,咱們一般將其標記在方法上便可,一般習慣將這個方法起名爲 init()

@PostConstruct
public void init() {
  System.out.println("Inside init() method...");
}
複製代碼

init-method

你應該見過這種初始化方式:

public class MyClass {
   public void init() {
      // perform post-creation logic here
   }
}

@Configuration
public class AppConfig {
   @Bean(initMethod = "init")
   public MyClass myclass() {
      return new MyClass ();
   }
}
複製代碼

你也應該見過這種配置方式:

<bean id="myClass" class="com.demo.MyClass" init-method="init"/>
複製代碼

沒錯,這只是一樣功能的不一樣實現方式罷了 以上就是三種初始化 Spring Beans 的方式,咱們在框架中看到過三種方式在組合使用,那麼組合使用的調用順序是什麼呢?

  1. 首先@PostConstruct 會被最早調用
  2. 其次 InitializingBean.afterPropertiesSet() 方法將會被調用
  3. 最後調用經過 XML 配置的 init-method 方法或經過設置 @Bean 註解 設置 initMethod 屬性的方法

瞭解了這些,你也就瞭解了 Spring Bean 是怎麼來的了

經過圖示來講明一下:

Xnip2019-07-01_21-46-24.jpg

組合shying,這個調用順序很難記憶嗎嗎?

PostConstruct (P),afterPropertiesSet (A),init-method (I) ---> PAI (圓周率π)

BeanPostProcessor

BeanPostProcessor 接口,你們也應該有印象,裏面只有兩個方法:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;

    Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
}
複製代碼

看方法名,BeforeInitialization 和 AfterInitialization,咱們應該猜得出,這是在上述三種方式的前和後,算是一種全局的切面思想,咱們常常會使用 postProcessAfterInitialization 方法,經過讀取 Bean 的註解完成一些後續邏輯編寫與屬性的設定,如今 Ready for Use以前是這樣:

Xnip2019-07-02_08-38-03.jpg

Ready for Use 以前,瞭解這些內容,已能夠基本知足平常的工做內容,但這並非 Ready for Use 的所有內容,Spring Bean 整個生命週期的流程應該是這樣的,後續文章會逐步點亮:

Xnip2019-07-02_08-48-24.jpg

靈魂追問

  1. 瞭解了 Spring Bean 是怎麼來的?那它是怎麼沒的呢?何時須要銷燬他們呢?
  2. Spring 框架中 XxxxAware,這些類有什麼做用,能在 Ready for Use 以前有用處嗎?
  3. 你平常的工做中有充分利用今天說明的這些內容嗎?懂得這些會大大方便你的編程

補充說明

  1. 雖然當下流行以註解聲明方式進行編程,甚至高版本 Spring 會將一些方法標記爲過期,但文章說明依舊會使用 XMLBeanFactory 這類方法,包括 XML 配置。這樣作,只不過爲了更清晰的說明問題。
  2. 另外將 Spring Bean 聲明週期的講解,進行拆分,是爲了讓你們有獨立的思考空間,帶着問題去思考、時間,而不是被動的填充,最終串聯起本身的學習網絡,這樣理解的更深入,具體請看以前寫的文章 程序猿爲何要看源碼, 後續內容請持續關注

歡迎持續關注公衆號:「日拱一兵」,後續會出一系列文章點亮 Spring Bean 週期圖,以完整代碼施力說明這個週期的順序;同時進行 Spring 知識點解釋與串聯,輕鬆搞定面試那點事,以及在工做中充分利用 Spring 的特性

推薦閱讀

相關文章
相關標籤/搜索