Spring學習5(3):Bean的生命週期
Spring學習5(3)
Bean生命週期由多個特定的生命階段組成,每個生命階段都開出介面,允許外界由此對Bean施加控制。 在spring中有兩個層面來定義Bean的生命週期,一個是Bean的作用範圍,一個是例項化Bean時所經歷的一系列階段。
BeanFactory中Bean的生命週期
生命週期圖解
具體呼叫過程如下:
- 當呼叫getBean()來請求某一個Bean時,如果容器註冊了
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
介面則會在例項化Bean之前,將呼叫介面的postProcessBeforeInstantiation()
- 根據配置情況呼叫Bean建構函式或工廠方法例項化Bean。
- 如果容器註冊了在步驟1中的那個介面那麼在例項化Bean後,可以呼叫介面的
postProcessAfterInstantiation()
方法來對已經例項化的物件做一點“梳妝打扮”。 - 如果Bean配置了屬性資訊,那麼容器在這一步將配置值設定到Bean對應屬性中,不過在設定每個屬性之前可以呼叫步驟1介面的
postProcessPropertyValues()
方法。 - 呼叫Bean的屬性設定方法設定屬性值。
- 如果Bean實現了
org.springframework.bean.factory.BeanNameAware
介面則將呼叫setBeanName()介面方法,將配置檔案中該Bean對應的名稱設定到Bean中。 - 如果Bean實現了
org.springframework.beans.factory.BeanFactoryAware
則將嗲用setBeanFactory()
方法將BeanFactory容器例項設定到Bean中。 - 如果BeanFactory裝配了
org.springframework.beans.factory.config.BeanPostProcessor
,則呼叫BeanPostProcessor的Objetc:postProcessBeforeInitialization(Object bean, String beanName)
這個函式提供當前正在處理的Bean以及beanName(當前Bean的配置名)返回加工處理後的Bean。這個方法可以對某些Bean進行特殊的處理,甚至改變Bean的行為,是spring框架中的重要方法,為容器提供對Bean進行後續加工處理的切入點,spring容器所提供的各種功能如Aop,動態代理等都經過BeanPostProcessor來實施。 - 如果Bean實現了InitializingBean的介面afterPropertiesSet()方法。
- 如果在
<bean>
中通過了init-method定義了初始化方法,則將執行這個方法。 - BeanPostProcessor除了步驟8中的方法還定義了
postProcessAfterInitialization(Object bean, String beanName)
方法,此時會呼叫這個方法讓容器再次獲得對Bean進行加工的機會。 - 如果在
<bean>
中指定Bean的作用範圍為scope="prototype"
則將Bean返回給呼叫者,spring不再管理Bean的生命週期;如果指定為scope="singletion"
則將Bean放入springIoC容器的快取池中,並將Bean引用放回給呼叫者,spring繼續對這些Bean進行後續的生命管理。 - 對於
scope="singleton"
的Bean(預設情況),當容器關閉時,如果Bean實現了DisposableBean介面,則將呼叫介面的destory()
方法,可以在此編寫釋放資源,記錄日誌等操作。 - 對於
scope="singletion"
的Bean,如果通過<bean>
的destroy-method屬性指定了Bean的銷燬方法,那麼Spring將執行Bean的這個方法,完成Bean資源的釋放。
Bean生命週期例項
採用之前用過的Car類,讓它實現所有Bean級的生命介面。 我們修改com.smart下Car.java檔案為如下程式碼:
package com.smart;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
public class Car implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean{
private String brand;
private String color;
private int maxSpeed;
private BeanFactory beanFactory;
private String beanName;
public Car() {
System.out.println("呼叫Car()建構函式。");
}
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
public void introduce() {
System.out.println("brand:"+brand+";color:"
+ color+";maxSpeed:"
+ maxSpeed+".");
}
public void setBrand(String brand) {
this.brand = brand;
System.out.println("呼叫setBrand()設定屬性。");
}
public void setColor(String color) {
this.color = color;
System.out.println("呼叫setColor()設定屬性。");
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
System.out.println("呼叫setMaxSpeed()設定屬性。");
}
//BeanFactoryAwawre介面方法
public void setBeanFactory(BeanFactory beanFactory) throws BeansException{
System.out.println("呼叫BeanFactoryAware.setBeanFactory().");
this.beanFactory = beanFactory;
}
//BeanNameAware介面方法
public void setBeanName(String beanName) {
System.out.println("呼叫BeanNameAware.setBeanName().");
this.beanName = beanName;
}
//InitializingBean介面方法
public void afterPropertiesSet() throws Exception{
System.out.println("呼叫InitializingBean.afterPropertiesSet().");
}
//DisposableBean介面方法
public void destroy() throws Exception{
System.out.println("呼叫DisposableBean.destroy().");
}
//通過<bean>的init-method屬性指定的初始化方法
public void myInit() {
System.out.println("呼叫init-method所指定的myInit(),將maxSpeed設定為240.");
this.maxSpeed = 240;
}
//通過<bean>的destroy-method屬性指定的銷燬方法
public void myDestroy() {
System.out.println("呼叫destroy-method所指定的myDestroy().");
}
}
這裡實現了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean等Bean級的生命週期介面,在下面定義了myInit()和myDestroy()方法,這兩個方法就可以在<bean>
中通過init-method和destroy-method方法。
MyInstantiationAwareBeanPostProcessor通過擴充套件InstantiationAwareBeanPostProcessor介面卡InstatiationAwareBeanPostProcessorAdapter提供實現。我們在com.smart.beanfactory中增加myInstantiationAwareBeanPostProcessor.java,程式碼如下:
package com.smart.beanfactory;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.
InstantiationAwareBeanPostProcessorAdapter;
import com.smart.Car;
public class MyInstantiationAwareBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter{
//介面:在例項化Bean前呼叫
public Object postProcessBeforeInstantiation(Class beanClass, String beanName)
throws BeansException{
if("car1".equals(beanName)) {
System.out.println("InstantiationAware BeanPostProcessor.postProcess"
+ " BeforeInstantiation");
}
return null;
}
//介面:在例項化Bean後呼叫
public boolean postProcessAfterInstantiation(Object bean, String beanName)
throws BeansException{
if("car1".equals(beanName)) {
System.out.println("InstantiationAware BeanPostProcessor.postProcess"
+ " AfterInstantiation");
}
return true;
}
//介面:在設定某個屬性時呼叫
public PropertyValues postProcessPropertyValues(
PropertyValues pvs,PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException{
if("car1".equals(beanName)) {
System.out.println("Instantiation AwareBeanPostProcessor.postProcess"
+ "PropertyValues");
}
return pvs;
}
}
除此之外spring還有一個BeanPostProcessor實現類,對配置檔案所提供的屬性設定值進行判斷,並執行相應的“補缺補漏操作”,在程式碼清單如下:
package com.smart.beanfactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.smart.Car;
public class MyBeanPostProcessor implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException{
if(beanName.equals("car1")) {
Car car = (Car)bean;
if(car.getColor() == null) {
System.out.println("呼叫BeanPostProcessor.postProcess"
+ " BeforeInitialization(), color is empty, default color is black");
car.setColor("黑色");
}
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException{
if(beanName.equals("car1")) {
Car car = (Car)(bean);
if(car.getMaxSpeed() >= 200) {
System.out.println("呼叫BeanPostProcessor.postProcess"
+ "AfterInitialization(), modify maxSpeed to 200.");
car.setMaxSpeed(200);
}
}
return bean;
}
}
註冊介面
上述這寫介面除了在Car.java中直接定義的介面其他的介面都需要註冊載入。首先我們在beans.xml中註冊myInit和myDestroy方法。程式碼更改如下:
<bean id="car1" class="com.smart.Car"
init-method="myInit"
destroy-method="myDestroy"
p:brand="紅旗CA72"
p:color="黑色"
p:maxSpeed="200"
/>
</beans>
下面讓容器裝載配置檔案,然後分別註冊上面所提供的兩個後處理器。在com.smart.beanfactory下建立BeanLifeCycle.java檔案,程式碼如下:
package com.smart.beanfactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.smart.Car;
public class BeanLifeCycle{
private static void LifeCycleInBeanFactory() {
//裝載配置檔案並啟動容器
Resource res = new ClassPathResource("com/smart/beanfactory/beans.xml");
BeanFactory bf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((DefaultListableBeanFactory)bf);
reader.loadBeanDefinitions(res);
//向容器註冊MyBeanPostProcessor後處理器
((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor());
//向容器中註冊MyInstantiationAwareBeanPostProcessor後處理器
((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
//第一次從容器中獲取car,將出發容器例項化Bean,將引發生命週期方法的呼叫
Car car1 = (Car)bf.getBean("car1");
car1.introduce();
car1.setColor("紅色");
//第二次從容器中獲取Car,直接從快取池中獲取
Car car2 = (Car)bf.getBean("car1");
//檢視car1和car2是否指向同一引用
System.out.println("car1 == car2:" + (car1==car2));
//關閉容器
((DefaultListableBeanFactory)bf).destroySingletons();
}
public static void main(String[] args) {
LifeCycleInBeanFactory();
}
}
這裡需要注意的是多個後處理器的呼叫順序和註冊順序無關,必須通過實現org.springframework.core.Ordered
介面來確定呼叫順序。
執行該程式碼即可基本瞭解呼叫的過程。
ApplicationContext中Bean的生命週期
書中給出的生命週期圖如下: 可以看到在Application只是多了幾個步驟:
- 如果Bean實現了
org.springframework.context.ApplicationContextAware
介面則會增加一個呼叫該介面方法setApplicationContext()
的步驟 - 如果在配置檔案中申明瞭後處理介面
BeanFactoryPostProcessor
的實現類,則應用上下文在裝載配置檔案之後,初始化例項之前將呼叫BeanFactoryPostProcessor
對配置資訊進行加工處理。
除此之外,ApplicationContext會利用java的反射機制自動識別出配置檔案中定義的BeanPostProcessor等後處理器並註冊到上下文中,而不像BeanFactory需要手工呼叫addBeanPostProcessor()進行註冊。
例項
假設我們希望對配置檔案中car1的brand配置屬性進行調整。在com.smart.context建立一個MyBeanFactoryPostProcessor.java,程式碼如下:
package com.smart.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import com.smart.Car;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
//對car的brand配置資訊進行加工操作
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf)
throws BeansException{
BeanDefinition bd = bf.getBeanDefinition("car1");
bd.getPropertyValues().addPropertyValue("brand", "奇瑞QQ");
System.out.println("呼叫BeanFactoryPostProcessor.postProcessBean Factory()");
}
}
ApplicationContext在啟動時,將首先為配置檔案中的每一個<bean>
生成一個BeanDefinition物件(<bean>
在spring容器中的內部表示)而後我們就有機會對其進行修改。
接下來對beans.xml修改:
<bean id="car1" class="com.smart.Car"
init-method="myInit"
destroy-method="myDestroy"
p:brand="紅旗CA72"
p:color="黑色"
p:maxSpeed="200"
/>
<bean id = "myBeanFactoryPostProcessor"
class = "com.smart.context.MyBeanFactoryPostProcessor"/>