《實戰錄》導語
雲端衛士《實戰錄》欄目定期會向粉絲朋友們分享一些在開發運維中的經驗和技巧,希望對於關注我們的朋友有所裨益。本期分享人爲雲端衛士安全運營工程師顧慶威,將帶來Spring中bean的生命週期的分享。
Spring作爲當前Java最流行、最強大的輕量級框架,受到了程序員的熱烈歡迎。準確的瞭解Spring Bean的生命週期是非常必要的。我們通常使用ApplicationContext作爲Spring容器。這裏,我們講的也是 ApplicationContext中Bean的生命週期。而實際上BeanFactory也是差不多的,只不過處理器需要手動註冊。
一
生命週期流程圖
Spring Bean的完整生命週期從創建Spring容器開始,直到最終Spring容器銷燬Bean,這其中包含了一系列關鍵點。
若容器註冊了以上各種接口,程序那麼將會按照以上的流程進行。下面將仔細講解各接口作用。
二
各種接口方法分類
Bean的完整生命週期經歷了各種方法調用,這些方法可以劃分爲以下幾類:
1、Bean的建立:容器尋找Bean的定義信息並將其實例化。
2、Setter注入執行Bean的屬性依賴注入。
3、BeanNameAware的setBeanName():如果Bean類有實現org.springframework.beans.BeanNameAware接口,工廠調用Bean的setBeanName()方法傳遞Bean的ID。
4、BeanFactoryAware的setBeanFactory():如果Bean類有實現org.springframework.beans.factory.BeanFactoryAware接口,工廠調用setBeanFactory()方法傳入工廠自身。
5、BeanPostProcessors的ProcessBeforeInitialization():如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean關聯,那麼其postProcessBeforeInitialization()方法將被將被調用。
6、initializingBean的afterPropertiesSet():如果Bean類已實現org.springframework.beans.factory.InitializingBean接口,則執行他的afterProPertiesSet()方法。
7、Bean定義文件中定義init-method:可以在Bean定義文件中使用"init-method"屬性設定方法名稱例如:如果有以上設置的話,則執行到這個階段,就會執行initBean()方法。
8、BeanPostProcessors的ProcessaAfterInitialization():如果有任何的BeanPostProcessors實例與Bean實例關聯,則執行BeanPostProcessors實例的ProcessaAfterInitialization()方法。
此時,Bean已經可以被應用系統使用,並且將保留在BeanFactory中知道它不在被使用。有兩種方法可以將其從BeanFactory中刪除掉。
9、DisposableBean的destroy():在容器關閉時,如果Bean類有實現org.springframework.beans.factory.DisposableBean接口,則執行他的destroy()方法。
10、Bean定義文件中定義destroy-method方法。
三
演示
我們用一個簡單的Spring Bean來演示一下Spring Bean的生命週期。
1、首先是一個簡單的Spring Bean,調用Bean自身的方法和Bean級生命週期接口方法,爲了方便演示,它實現了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這4個接口,同時有2個方法,對應配置文件中<bean>的init-method和destroy-method。如下:
import
org.springframework.beans.BeansException; import
org.springframework.beans.factory.BeanFactory; import
org.springframework.beans.factory.BeanFactoryAware; import
org.springframework.beans.factory.BeanNameAware; import
org.springframework.beans.factory.DisposableBean; import
org.springframework.beans.factory.InitializingBean; public class
Person
implements
BeanFactoryAware, BeanNameAware,InitializingBean, DisposableBean {
private
String
name;
private
String
address;
private int
phone;
private
BeanFactory
beanFactory;
private
String
beanName;
public
Person() { System.out.println("【構造器】調用Person的構造器實例化"); }
public
String getName() {
return
name; }
public void
setName(String name) { System.out.println("【注入屬性】注入屬性name");
this.name
= name; }
public
String getAddress() {
return
address; }
public void
setAddress(String address) { System.out.println("【注入屬性】注入屬性address");
this.address
= address; }
public int
getPhone() {
return
phone; }
public void
setPhone(int
phone) { System.out.println("【注入屬性】注入屬性phone");
this.phone
= phone; }
@Override
public
String toString() {
return
"Person [address="
+
address
+
", name="
+
name
+
", phone=" +
phone
+
"]"; }
// 這是BeanFactoryAware接口方法 @Override
public void
setBeanFactory(BeanFactory arg0)
throws
BeansException { System.out.println("【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()");
this.beanFactory
= arg0; }
// 這是BeanNameAware接口方法 @Override
public void
setBeanName(String arg0) { System.out.println("【BeanNameAware接口】調用BeanNameAware.setBeanName()");
this.beanName
= arg0; }
// 這是InitializingBean接口方法 @Override
public void
afterPropertiesSet()
throws
Exception { System.out.println("【InitializingBean接口】調用InitializingBean.afterPropertiesSet()"); }
// 這是DiposibleBean接口方法 @Override
public void
destroy()
throws
Exception { System.out.println("【DiposibleBean接口】調用DiposibleBean.destory()"); }
// 通過<bean>的init-method屬性指定的初始化方法
public void
myInit() { System.out.println("【init-method】調用<bean>的init-method屬性指定的初始化方法"); }
// 通過<bean>的destroy-method屬性指定的初始化方法
public void
myDestory() { System.out.println("【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法"); } }
|
2、接下來是演示BeanPostProcessor接口的方法,如下:
import
org.springframework.beans.BeansException; import
org.springframework.beans.factory.config.BeanPostProcessor; public class
MyBeanPostProcessor
implements
BeanPostProcessor {
public
MyBeanPostProcessor() {
super(); System.out.println("這是BeanPostProcessor實現類構造器!!");
//
TODO Auto-generated constructor stub }
@Override
public
Object postProcessAfterInitialization(Object arg0, String arg1)
throws
BeansException { System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!");
return
arg0; }
@Override
public
Object postProcessBeforeInitialization(Object arg0, String arg1)
throws
BeansException { System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!");
return
arg0; } }
|
如上,BeanPostProcessor接口包括2個方法postProcessAfterInitialization和postProcessBeforeInitialization,這兩個方法的第一個參數都是要處理的Bean對象,第二個參數都是Bean的name。返回值也都是要處理的Bean對象。這裏要注意。
3、InstantiationAwareBeanPostProcessor 接口本質是BeanPostProcessor的子接口,一般我們繼承Spring爲其提供的適配器類InstantiationAwareBeanPostProcessor Adapter來使用它,如下:
import
java.beans.PropertyDescriptor;
import
org.springframework.beans.BeansException; import
org.springframework.beans.PropertyValues; import
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; public class
MyInstantiationAwareBeanPostProcessor
extends
InstantiationAwareBeanPostProcessorAdapter
{
public
MyInstantiationAwareBeanPostProcessor() {
super(); System.out.println("這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!); }
// 接口方法、實例化Bean之前調用 @Override public
Object postProcessBeforeInstantiation(Class beanClass, String beanName)
throws
BeansException { System.out.println("InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法");
return null; } //
接口方法、實例化Bean之後調用 @Override
public
Object postProcessAfterInitialization(Object bean, String beanName)
throws
BeansException { System.out.println("InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法");
return
bean; }
//
接口方法、設置某個屬性時調用 @Override
public
PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws
BeansException { System.out.println("InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法");
return
pvs; }
}
|
這個有3個方法,其中第二個方法postProcessAfterInitialization就是重寫了BeanPostProcessor的方法。第三個方法postProcessPropertyValues用來操作屬性,返回值也應該是PropertyValues對象。
4、演示工廠後處理器接口方法,如下:
package
springBeanTest; 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; public class
MyBeanFactoryPostProcessor
implements
BeanFactoryPostProcessor {
public
MyBeanFactoryPostProcessor() {
super(); System.out.println("這是BeanFactoryPostProcessor實現類構造器!!"); }
@Override
public void
postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws
BeansException { System.out .println("BeanFactoryPostProcessor調用postProcessBeanFactory方法"); BeanDefinition bd = arg0.getBeanDefinition("person"); bd.getPropertyValues().addPropertyValue("phone",
"110"); } }
|
5、配置文件如下beans.xml,很簡單,使用ApplicationContext,處理器不用手動註冊:
<?xml
version="1.0"
encoding="UTF-8"?> <beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean
id="beanPostProcessor"
class="springBeanTest.MyBeanPostProcessor">
</bean> <bean
id="instantiationAwareBeanPostProcessor"
class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
</bean> <bean
id="beanFactoryPostProcessor"
class="springBeanTest.MyBeanFactoryPostProcessor">
</bean> <bean
id="person"
class="springBeanTest.Person"
init-method="myInit" destroy-method="myDestory"
scope="singleton"
p:name="張三"
p:address="廣州"
p:phone="15900000000"
/> </beans>
|
6、下面測試一下:
import
org.springframework.context.ApplicationContext; import
org.springframework.context.support.ClassPathXmlApplicationContext; public class
BeanLifeCycle {
public static void
main(String[] args) { System.out.println("現在開始初始化容器");
ApplicationContext
factory =
new
ClassPathXmlApplicationContext("springBeanTest/beans.xml"); System.out.println("容器初始化成功");
//得到Preson,並使用 Person person = factory.getBean("person",Person.class); System.out.println(person);
System.out.println("現在開始關閉容器!"); ((ClassPathXmlApplicationContext)factory).registerShutdownHook(); } }
|
關閉容器使用的是實際是AbstractApplicationContext的鉤子方法。
我們來看一下結果:
現在開始初始化容器
這是BeanFactoryPostProcessor實現類構造器!!
BeanFactoryPostProcessor調用postProcessBeanFactory方法
這是BeanPostProcessor實現類構造器!!
這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!
InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法
【構造器】調用Person的構造器實例化
InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法
【注入屬性】注入屬性address
【注入屬性】注入屬性name
【注入屬性】注入屬性phone
【BeanNameAware接口】調用BeanNameAware.setBeanName()
【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
【InitializingBean接口】調用InitializingBean.afterPropertiesSet()
【init-method】調用<bean>的init-method屬性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法
容器初始化成功
Person [address=廣州, name=張三, phone=110]
現在開始關閉容器!
【DiposibleBean接口】調用DiposibleBean.destory()
【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法
|
實際上,ApplicationContext除了向BeanFactory那樣維護容器外,還提供了更加豐富的框架功能,如Bean的消息,事件處理機制等,這個可自行了解。