通過前面多個接口的介紹了解了Bean對象生命周期相關的方法,本文就将這些接口的方法串起來,來了解Bean的完整的生命周期。而介紹Bean的生命周期也是面試過程中經常會碰到的一個問題,如果不注意就跳坑裡啦~~
Spring之Bean對象的初始化和銷毀方法
Spring之InitializingBean接口和DisposableBean接口介紹
Spring之Aware接口介紹
Spring之InstantiationAwareBeanPostProcessor接口介紹
Spring之BeanFactoryPostProcessor接口介紹
Spring之BeanPostProcessor(後置處理器)介紹
建議:看此文前請将上面相關的内容熟悉下,便于了解下面的内容。
文章目錄
Bean生命周期
一、調用過程
二、生命周期方法說明
三、示範
1.BeanFactoryPostProcessor接口
2.BeanPostProcessor接口
3.InstantiationAwareBeanPostProcessor接口
4.BeanNameAware,BeanFactoryAware等Aware接口
5.InitializingBean,DisposableBean接口
6.@PostConstruct和@PreDestroy注解
7.init-method,destroy-method
8.測試
四、Bean對象生命周期總結
Bean生命周期
一、調用過程
二、生命周期方法說明
接口 方法 說明
BeanFactoryPostProcessor postProcessBeanFactory 在Bean對象執行個體化之前執行, 通過beanFactory可以擷取bean的定義資訊, 并可以修改bean的定義資訊。這點是和BeanPostProcessor最大差別
BeanPostProcessor postProcessBeforeInitialization 執行個體化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務
postProcessAfterInitialization 執行個體化、依賴注入、初始化完畢時執行
InstantiationAwareBeanPostProcessor postProcessBeforeInstantiation 在方法執行個體化之前執行,傳回結果為null正常執行,傳回結果如果不為null則會跳過相關方法而進入初始化完成後的流程
postProcessAfterInstantiation 在方法執行個體化之後執行,傳回結果true才會執行postProcessPropertyValues方法
postProcessPropertyValues 可以用來修改Bean中屬性的内容
InitializingBean afterPropertiesSet 初始化的方法
DisposableBean destroy 容器銷毀前的回調方法
Aware setXXX 感覺對應Spring容器的内容
@PostConstruct 标注在方法頭部,表示初始化的方法
@PreDestroy 标注在方法頭部,表示銷毀前回調的方法
init-method屬性 指定初始化的方法
destory-method屬性 指定銷毀前的回調方法
三、示範
1.BeanFactoryPostProcessor接口
該接口中的方法是最先執行的。在Bean執行個體化之前執行
/**
* 自定義BeanFactoryPostProcessor
*
* @author dengp
*
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
/**
* 本方法在Bean對象執行個體化之前執行,
* 通過beanFactory可以擷取bean的定義資訊,
* 并可以修改bean的定義資訊。這點是和BeanPostProcessor最大差別
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("****** BeanFactoryPostProcessor 開始執行了");
/*String[] names = beanFactory.getBeanDefinitionNames();
for (String name : names) {
if("user".equals(name)){
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
// MutablePropertyValues如果設定了相關屬性,可以修改,如果沒有設定則可以添加相關屬性資訊
if(propertyValues.contains("name")){
propertyValues.addPropertyValue("name", "bobo");
System.out.println("修改了屬性資訊");
}
}
}*/
System.out.println("******* BeanFactoryPostProcessor 執行結束了");
}
}
2.BeanPostProcessor接口
該接口中定義了兩個方法,分别在Bean對象執行個體化及裝配後在初始化的前後執行
/**
* 自定義BeanPostProcessor實作類
* BeanPostProcessor接口的作用是:
* 我們可以通過該接口中的方法在bean執行個體化、配置以及其他初始化方法前後添加一些我們自己的邏輯
* @author dengp
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* 執行個體化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務
* 注意:方法傳回值不能為null
* 如果傳回null那麼在後續初始化方法将報空指針異常或者通過getBean()方法擷取不到bena執行個體對象
* 因為後置處理器從Spring IoC容器中取出bean執行個體對象沒有再次放回IoC容器中
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println(">>後置處理器 before方法:"+bean+"\t"+beanName);
}
// 可以根據beanName不同執行不同的處理操作
return bean;
}
/**
* 執行個體化、依賴注入、初始化完畢時執行
* 注意:方法傳回值不能為null
* 如果傳回null那麼在後續初始化方法将報空指針異常或者通過getBean()方法擷取不到bena執行個體對象
* 因為後置處理器從Spring IoC容器中取出bean執行個體對象沒有再次放回IoC容器中
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println("<<後置處理器after方法:"+bean+"\t"+beanName);
}
// 可以根據beanName不同執行不同的處理操作
return bean;
}
}
3.InstantiationAwareBeanPostProcessor接口
該接口是BeanPostProcessor接口的子接口,是以該接口肯定具有BeanPostProcessor接口的功能,同時又定義了三個自己的接口,這三個接口是在Bean執行個體化前後執行的方法。
/**
* 自定義處理器
* @author dengp
*
*/
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{
/**
* BeanPostProcessor接口中的方法
* 在Bean的自定義初始化方法之前執行
* Bean對象已經存在了
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if("user".equals(beanName)){
System.out.println("【---InstantiationAwareBeanPostProcessor---】 postProcessBeforeInitialization");
}
return bean;
}
/**
* BeanPostProcessor接口中的方法
* 在Bean的自定義初始化方法執行完成之後執行
* Bean對象已經存在了
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println("【--InstantiationAwareBeanPostProcessor----】 postProcessAfterInitialization");
}
return bean;
}
/**
* InstantiationAwareBeanPostProcessor中自定義的方法
* 在方法執行個體化之前執行 Bean對象還沒有
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessBeforeInstantiation");
}
return null;
}
/**
* InstantiationAwareBeanPostProcessor中自定義的方法
* 在方法執行個體化之後執行 Bean對象已經建立出來了
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessAfterInstantiation");
}
return true;
}
/**
* InstantiationAwareBeanPostProcessor中自定義的方法
* 可以用來修改Bean中屬性的内容
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
if("user".equals(beanName)){
System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessPropertyValues--->");
}
return pvs;
}
}
4.BeanNameAware,BeanFactoryAware等Aware接口
Aware接口是用來讓對象感覺目前的IOC環境
5.InitializingBean,DisposableBean接口
這兩個接口是Bean初始化及銷毀回調的方法。
6.@PostConstruct和@PreDestroy注解
package com.dpb.pojo;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
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;
/**
* 實作InitializingBean和DisposableBean接口
* @author dengp
*
*/
public class User implements InitializingBean,DisposableBean,BeanNameAware,BeanFactoryAware{
private int id;
private String name;
//感覺本對象在Spring容器中的id屬性
private String beanName;
// 感覺本對象所屬的BeanFactory對象
private BeanFactory factory;
public User(){
System.out.println("構造方法被執行了...User 被執行個體化");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("《注入屬性》注入name屬性"+name);
this.name = name;
}
public String getBeanName() {
return beanName;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", beanName=" + beanName + "]";
}
/**
* bean對象銷毀前的回調方法
*/
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("《DisposableBean接口》destory ....");
}
/**
* 初始化的方法
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化:《InitializingBean接口》afterPropertiesSet....");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("【BeanFactoryAware接口】setBeanFactory");
this.factory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("【BeanNameWare接口】setBeanName");
this.beanName = name;
}
public BeanFactory getFactory() {
return factory;
}
/**
* 也是個初始化的方法
*/
@PostConstruct
public void postConstruct(){
System.out.println("初始化:【@PostConstruct】執行了...");
}
/**
* 銷毀前的回調方法
*/
@PreDestroy
public void preDestory(){
System.out.println("【@preDestory】執行了...");
}
/**
* 初始化的方法
* 通過bean标簽中的 init-method屬性指定
*/
public void start(){
System.out.println("初始化:【init-method】方法執行了....");
}
/**
* 銷毀前的回調方法
* 通過bean标簽中的 destory-method屬性指定
*/
public void stop(){
System.out.println("【destory-method】方法執行了....");
}
}
7.init-method,destroy-method
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:annotation-config/>
<bean class="com.dpb.pojo.User" id="user" init-method="start" destroy-method="stop" >
<property name="name" value="波波烤鴨"></property>
</bean>
<!-- 注冊後置處理器 -->
<bean class="com.dpb.processor.MyBeanPostProcessor"/>
<!-- 注冊 InstantiationAwareBeanPostProcessor -->
<bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
<!-- 注冊 BeanFactoryPostProcessor對象-->
<bean class="com.dpb.factoryprocessor.MyBeanFactoryPostProcessor"/>
</beans>
8.測試
@Test
public void test1() {
System.out.println("Spring容器開始加載....");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = ac.getBean(User.class);
System.out.println("---------------"+user);
ac.registerShutdownHook();
System.out.println("Spring容器解除安裝完成....");
}
輸出結果
Spring容器開始加載....
三月 04, 2019 11:14:38 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
資訊: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@707f7052: startup date [Mon Mar 04 23:14:38 CST 2019]; root of context hierarchy
三月 04, 2019 11:14:39 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
資訊: Loading XML bean definitions from class path resource [applicationContext.xml]
****** BeanFactoryPostProcessor 開始執行了
******* BeanFactoryPostProcessor 執行結束了
【--InstantiationAwareBeanPostProcessor----】postProcessBeforeInstantiation
構造方法被執行了...User 被執行個體化
【--InstantiationAwareBeanPostProcessor----】postProcessAfterInstantiation
【--InstantiationAwareBeanPostProcessor----】postProcessPropertyValues--->
《注入屬性》注入name屬性波波烤鴨
【BeanNameWare接口】setBeanName
【BeanFactoryAware接口】setBeanFactory
>>後置處理器 before方法:User [id=0, name=波波烤鴨, beanName=user] user
【---InstantiationAwareBeanPostProcessor---】 postProcessBeforeInitialization
初始化:【@PostConstruct】執行了...
初始化:《InitializingBean接口》afterPropertiesSet....
初始化:【init-method】方法執行了....
<<後置處理器after方法:User [id=0, name=波波烤鴨, beanName=user] user
【--InstantiationAwareBeanPostProcessor----】 postProcessAfterInitialization
---------------User [id=0, name=波波烤鴨, beanName=user]
Spring容器解除安裝完成....
三月 04, 2019 11:14:39 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
資訊: Closing org.springframework.context.support.ClassPathXmlApplicationContext@707f7052: startup date [Mon Mar 04 23:14:38 CST 2019]; root of context hierarchy
【@preDestory】執行了...
《DisposableBean接口》destroy ....
【destory-method】方法執行了....
四、Bean對象生命周期總結
如果實作了BeanFactoryPostProcessor接口,那麼在容器啟動的時候,該接口中的postProcessBeanFactory方法可以修改Bean中中繼資料中的資訊。該方法是在執行個體化對象之前執行
如果實作了InstantiationAwareBeanPostProcessor接口,那麼在執行個體化Bean對象之前會調用postProcessBeforeInstantiation方法,該方法如果傳回的不為null則會直接調用postProcessAfterInitialization方法,而跳過了Bean執行個體化後及初始化前的相關方法,如果傳回null則正常流程,postProcessAfterInstantiation在執行個體化成功後執行,這個時候對象已經被執行個體化,但是該執行個體的屬性還未被設定,都是null。因為它的傳回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法傳回false,并且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果傳回true, postProcessPropertyValues就會被執行,postProcessPropertyValues用來修改屬性,在初始化方法之前執行。
如果實作了Aware相關的結果,那麼相關的set方法會在初始化之前執行。
如果實作了BeanPostProcessor接口,那麼該接口的方法會在執行個體化後的初始化方法前後執行。
如果實作了InitializingBean接口則在初始化的時候執行afterPropertiesSet
如果指定了init-method屬性則在初始化的時候會執行指定的方法。
如果指定了@PostConstruct則在初始化的時候會執行标注的方法。
到此對象建立完成
當對象需要銷毀的時候。
如果實作了DisposableBean接口會執行destroy方法
如果指定了destroy-method屬性則會執行指定的方法
如果指定了@PreDestroy注解則會執行标注的方法
~ 這就是Bean對象的生命周期了。有問題的歡迎留言