Spring bean生命週期簡介說明
轉發
http://java265.com/JavaFramework/Spring/202107/504.html
我們都知道,在使用new關鍵字例項化的Java Bean,它的生命週期非常簡單,當Java Bean不需要使用時,則Java會自動進行垃圾回收,
所以它的生命週期會非常容易理解。
但Spring中Bean的生命週期,則較為複雜,它由Bean定義->Bean初始化->Bean應用->Bean銷燬
Spring 針對不同Bean的作用域採用不同的管理方式
對採用singleton 作用域Bean,Spring可清楚的知道它的建立及初始化時間及銷燬時間,
但是對於prototype作用域下的Bean,Spring框架則只負責建立,當建立完畢後,則將Bean例項交給客戶端程式碼管理,
Spring將不對此型別的Bean進行生命週期管理
Spring Bean生命週期執行流程
Spring 容器在確保一個 Bean 能夠使用之前,會進行很多工作。Spring 容器中 Bean 的生命週期流程如下圖所示
Bean 生命週期流程
- Spring 啟動,查詢並載入需要被Spring 管理的 Bean,並例項化 Bean。
- 利用依賴注入完成 Bean 中所有屬性值的配置注入。
- 當Bean 實現了 BeanNameAware 介面,則 Spring 呼叫 Bean 的 setBeanName() 方法傳入當前 Bean 的 id 值。
- 當Bean 實現了 BeanFactoryAware 介面,則 Spring 呼叫 setBeanFactory() 方法傳入當前工廠例項的引用。
- 當Bean 實現了 ApplicationContextAware 介面,則 Spring 呼叫 setApplicationContext() 方法傳入當前 ApplicationContext 例項的引用。
- 當Bean 實現了 BeanPostProcessor 介面,則 Spring 呼叫該介面的預初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操作,此處非常重要,Spring 的 AOP 就是利用它實現的。
- 當Bean 實現了 InitializingBean 介面,則 Spring 將呼叫 afterPropertiesSet() 方法。
- 當在配置檔案中通過 init-method 屬性指定了初始化方法,則呼叫該初始化方法。
- 當BeanPostProcessor 和 Bean 關聯,則 Spring 將呼叫該介面的初始化方法 postProcessAfterInitialization()。此時,Bean 已經可以被應用系統使用了。
- 當在 <bean> 中指定了該 Bean 的作用域為 singleton,則將該 Bean 放入 Spring IoC 的快取池中,觸發 Spring 對該 Bean 的生命週期管理;如果在 <bean> 中指定了該 Bean 的作用域為 prototype,則將該 Bean 交給呼叫者,呼叫者管理該 Bean 的生命週期,Spring 不再管理該 Bean。
- 當Bean 實現了 DisposableBean 介面,則 Spring 會呼叫 destory() 方法銷燬 Bean;如果在配置檔案中通過 destory-method 屬性指定了 Bean 的銷燬方法,則 Spring 將呼叫該方法對 Bean 進行銷燬。
Spring 為 Bean 提供了細緻全面的生命週期過程,實現特定的介面或設定 <bean> 的屬性都可以對 Bean 的生命週期過程產生影響。建議不要過多的使用 Bean 實現介面,因為這樣會導致程式碼的耦合性過高。
瞭解 Spring 生命週期的意義就在於,可以利用 Bean 在其存活期間的指定時刻完成一些相關操作。一般情況下,會在 Bean 被初始化後和被銷燬前執行一些相關操作。
Spring 官方提供了 3 種方法實現初始化回撥和銷燬回撥:
- 實現 InitializingBean 和 DisposableBean 介面;
- 在 XML 中配置 init-method 和 destory-method;
- 使用 @PostConstruct 和 @PreDestory 註解。
在一個 Bean 中有多種生命週期回撥方法時,優先順序為:註解 > 介面 > XML。
不建議使用介面和註解,這會讓 pojo 類和 Spring 框架緊耦合。
初始化回撥
1. 使用介面
org.springframework.beans.factory.InitializingBean 介面提供了以下方法:
- void afterPropertiesSet() throws Exception;
您可以實現以上介面,在 afterPropertiesSet 方法內指定 Bean 初始化後需要執行的操作。
<bean id="..." class="..." /> public class User implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("呼叫介面:InitializingBean,方法:afterPropertiesSet,無引數"); } }
2. 配置XML
可以通過 init-method 屬性指定 Bean 初始化後執行的方法
<bean id="..." class="..." init-method="init"/> public class User { public void init() { System.out.println("呼叫init-method指定的初始化方法:init" ); } }
3. 使用註解
使用 @PostConstruct 註解標明該方法為 Bean 初始化後的方法。
public class ExampleBean { @PostConstruct public void init() { System.out.println("@PostConstruct註解指定的初始化方法:init" ); } }
銷燬回撥
1. 使用介面
org.springframework.beans.factory.DisposableBean 介面提供了以下方法: void destroy() throws Exception;
您可以實現以上介面,在 destroy 方法內指定 Bean 初始化後需要執行的操作。
<bean id="..." class="..." /> public class User implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("呼叫介面:InitializingBean,方法:afterPropertiesSet,無引數"); } }
2. 配置XML
可以通過 destroy-method 屬性指定 Bean 銷燬後執行的方法
<bean id="..." class="..." destroy-method="destroy"/> public class User { public void destroy() { System.out.println("呼叫destroy-method指定的銷燬方法:destroy" ); } }
3. 使用註解
使用 @PreDestory 註解標明該方法為 Bean 銷燬前執行的方法。
public class ExampleBean { @PreDestory public void destroy() { System.out.println("@PreDestory註解指定的初始化方法:destroy" ); } }
例
下面使用 Eclipse IDE 演示如何通過配置 XML 的方式實現初始化回撥和銷燬回撥,步驟如下:
- 建立 SpringDemo 專案,並在 src 目錄下建立 com.java265包。
- 新增相應的 jar 包,可以參考《第一個Spring程式》一節。
- 在 com.java265 包下建立 HelloWorld 和 MainApp 類。
- 在 src 目錄下建立 Spring 配置檔案 Beans.xml。
- 執行 SpringDemo 專案
HelloWorld 類-----
package com.java265; public class HelloWorld { private String message; public void setMessage(String message) { this.message = message; } public void getMessage() { System.out.println("message : " + message); } public void init() { System.out.println("Bean正在進行初始化"); } public void destroy() { System.out.println("Bean將要被銷燬"); } }
MainApp 類程式碼如下,該類中我們使用 AbstractApplicationContext 類的 registerShutdownHook() 方法,來確保正常關機並呼叫相關的 destroy() 方法。
package com.java265; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); context.registerShutdownHook(); } }
Beans.xml 配置檔案程式碼如下。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="helloWorld" class="com.java265.HelloWorld" init-method="init" destroy-method="destroy"> <property name="message" value="Hello World!" /> </bean> </beans>
-----執行結果-----
Bean正在進行初始化
message : Hello World!
Bean將要被銷燬
預設的初始化和銷燬方法
如果多個 Bean 需要使用相同的初始化或者銷燬方法,不用為每個 bean 宣告初始化和銷燬方法,可以使用 default-init-method 和 default-destroy-method 屬性,如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-init-method="init" default-destroy-method="destroy"> <bean id="..." class="..."> ... </bean> </beans>