Spring Bean生命周期的各阶段介绍
一.xml方式配置bean
二.Aware接口
2.1BeanNameAware
2.2BeanFactoryAware
2.3ApplicationContextAware
2.4 Aware各接口的執行順序
2.4Aware接口總結
三.BeanPostProcessor接口
四.InitializingBean接口
五.init-method方法
六.DestructionAwareBeanPostProcessor接口
七.DisposableBean接口
八.destory-method方法
九.生命周期大雜燴
9.1 實現多接口的Student類
9.2 BeanPostProcessor前后置處理
9.3 DestructionAwareBeanPostPrecessor接口
9.4 配置xml文件
9.5 測試代碼
9.6 輸出結果
十.總結
Spring Bean的生命周期是一個老生常談的問題了,網上一搜一大把,無非就是畫一幅流程圖(比如下面這幅圖),然后用語言介紹創建bean后執行各Aware接口,然后BeanPostProcessor.....最終Bean創建成功了,就可以使用這個Bean了,然后在容器銷毀的時候,又會執行一些操作。
其實對于上面的提到的流程圖,注意上面的圖只是Spring Bean的大概流程(省略了一部分),主要涉及到了5個接口,分別是XxxAware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean接口,本文將會對這幾個接口,以及init-method、destroy-method做相關的使用介紹,在明白怎么使用后,再把他們串起來,這樣的話,對于Spring Bean的生命周期就差不多知道咋回事了,而不用死記硬背。
一. xml方式配置Bean
在說Aware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean這些接口前,先簡單回顧一下使用xml配置并獲取一個Student類的bean過程,后面介紹各個接口的使用方式時時,也是按照這個形式;
1.1 創建Student類
平淡無奇的Student類:
package cn.ganlixin.entity;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
public class Student {
private Integer id;
private String name;
}
1.2 創建配置文件
平淡無奇的applicationContext.xml配置文件,創建一個student bean,利用setter方式設置初始值:
<?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.xsd">
<bean class="cn.ganlixin.entity.Student" id="student">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
</beans>
1.3 測試
創建一個Main類,用于測試
package cn.ganlixin;
import cn.ganlixin.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
@Slf4j
public class Test {
public static void main(String[] args) {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Student student = beanFactory.getBean("student", Student.class);
log.info("測試程序獲取到的student bean:{}", student);
}
}
下面是運行程序的輸出,可以看到和預期相符,創建一個Student的bean,id和name默認值為99、張三;
INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
二.Aware接口
Aware接口有很多實現類,本文只介紹BeanNameAware、BeanFactoryAware、ApplicationContextAware,關系如下:
2.1 BeanNameAware
創建一個Student類,讓該類實現BeanNameAware接口,并且重寫setBeanName方法
@Data
@Slf4j
public class Student implements BeanNameAware {
private Integer id;
private String name;
/**
* 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
*
* @param s bean的id
*/
@Override
public void setBeanName(String s) {
log.info("beanName:{}, student bean:{}", s, this);
this.id = 100;
log.info("將beanName:{}的id改為100", s);
}
}
配置文件和測試程序都不改變,運行測試程序,輸出內容如下:
INFO [main] cn.ganlixin.entity.Student - beanName:student, student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - 將beanName:student的id改為100 INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=100, name=張三)
可以看到,實現BeanNameAware接口后,重寫setBeanName的方法中,獲取到的student bean,是已經初始化的bean(屬性都已經有值了),并且setBeanName方法中可以對當前的bean進行各種操作,包括修改bean的某些屬性,最后獲取到的bean是已經修改后的bean。
這里只是簡單介紹了一下BeanNameAware接口的用法,使用BeanNameAware接口,可以對當前Bean進行操作。
2.2 BeanFactoryAware
創建Student類,實現BeanFactoryAware接口,并且重寫setBeanFactory方法
@Data
@Slf4j
public class Student implements BeanFactoryAware {
private Integer id;
private String name;
/**
* 實現BeanFactoryAware接口后,需重寫setBeanFactroy方法
*
* @param beanFactory 創建該bean的beanFactory
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// 可以在setBeanFactory方法中獲取、修改beanFactory中的所有bean
log.info("student this bean:{}", this);
Student student = beanFactory.getBean("student", Student.class);
log.info("通過beanFactory獲取student bean:{}", student);
// 將name設置為李四
this.name = "李四";
}
}
運行輸出如下:
INFO [main] cn.ganlixin.entity.Student - student this bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - 通過beanFactory獲取student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=李四)
通過上面的代碼輸出結果可以看出,實現BeanFactoryAware接口后,可以在setBeanFactory方法中操作BeanFactory的所有bean,操作的范圍要比BeanNameAware要大。
2.3 ApplicationContextAware
ApplicationContext,有多種稱呼,比如“應用容器”、“環境”、“上線文”...
創建Student類,實現ApplicationContextAware接口,并且重寫setApplicationContext接口:
@Data
@Slf4j
public class Student implements ApplicationContextAware {
private Integer id;
private String name;
/**
* 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
*
* @param applicationContext 該bean所在的上下文(applicationContext、容器)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("Student this:{}", this);
final Student student = applicationContext.getBean("student", Student.class);
final Environment environment = applicationContext.getEnvironment();
log.info("student bean:{}", student);
log.info("env -> user.dir:{}", environment.getProperty("user.dir"));
}
}
需要修改一下測試程序,測試程序中加載配置時使用的XmlBeanFactory,而XmlBeanFactory不會回調ApplicationContextAware接口的setApplicationContext方法,下面使用ClassPathXmlApplicationContext類來加載配置:
@Slf4j
public class Test {
public static void main(String[] args) {
//BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
// 使用ApplicationContext來加載配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = context.getBean("student", Student.class);
log.info("測試程序獲取到的student bean:{}", student);
}
}
運行測試程序:
INFO [main] cn.ganlixin.entity.Student - Student this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - env -> user.dir:/Users/ganlixin/code/java-code-all/spring INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
實現ApplicationContextAware接口后,在setApplicationContext方法中,入參是當前的applicationContext,也就是說,可以在該方法中對Spring容器進行設置,操作的范圍又要比BeanFactoryAware的setBeanFactory要廣得多。
2.4 Aware各接口執行的先后順序
既然有這幾個Aware接口,如果一個類同時實現了這3個接口,那么執行順序是怎樣的呢?下面就來測試一下。
創建Student類,分別實現BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,并重寫其接口的方法:
@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
private Integer id;
private String name;
/**
* 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
*
* @param s bean的id
*/
@Override
public void setBeanName(String s) {
log.info("call BeanNameAware.setBeanName()");
}
/**
* 實現BeanFactoryAware接口后,需重寫setBeanFactroy
*
* @param beanFactory 創建該bean的bean工廠
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("call BeanFactoryAware.setBeanFactory()");
}
/**
* 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
*
* @param applicationContext 該bean所在的上下文(applicationContext、容器)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("call ApplicationContextAware.setApplicationContext()");
}
}
仍舊使用ClassPathXmlApplicationContext類來加載配置,運行輸出結果如下:
INFO [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName() INFO [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory() INFO [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext() INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
2.4 Aware接口總結
上面演示了Spring中幾個Aware接口的用法和特點,下面總結一下:
1.實現BeanNameAware接口后,重寫setBeanName方法,可以對單個Bean進行擴展修改;
2.實現BeanFactoryAware接口后,重寫setBeanFactory方法,可以對bean工廠中的所有Bean進行擴展修改;
3.實現ApplicationContextAware接口后,重寫setApplicationContext方法后,可以對整個容器進行擴展修改;
4.這幾個接口的執行順序分別是BeanNameAware->BeanFactoryAware->ApplicationContextAware;
三.BeanPostProcessor接口
BeanPostProcessor和前面的Aware接口有些區別,通過下面的例子就能看出區別在哪里!
下面舉個例子,創建MyBeanPostProcessor類,實現BeanPostProcessor接口,注意,這里沒有在Student類上實現BeanPostProcessor接口。
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 實現了BeanPostProcessor接口后,重寫postProcessBeforeInitialization,在各種Aware接口執行完畢后執行該方法
*
* @param bean 本次處理的bean
* @param beanName 本次處理的beanName(bean id)
* @return 返回的是在本方法中處理后的bean
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean);
return bean;
}
/**
* 實現了BeanPostProcessor接口后,重寫postProcessBeforeInitialization,在initMethod方法執行完畢后執行該方法
*
* @param bean 本次處理的bean
* @param beanName 本次處理的beanName(bean id)
* @return 返回的是在本方法中處理后的bean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean);
return bean;
}
}
創建兩個類,分別是Student和User類,其中Use類沒有實現Aware接口,Student類實現了前面提到的3個Aware接口
@Data
public class User {
private Integer id;
private String name;
}
@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
private Integer id;
private String name;
/**
* 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
*
* @param s bean的id
*/
@Override
public void setBeanName(String s) {
log.info("call BeanNameAware.setBeanName()");
}
/**
* 實現BeanFactoryAware接口后,需重寫setBeanFactroy
*
* @param beanFactory 創建該bean的bean工廠
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("call BeanFactoryAware.setBeanFactory()");
}
/**
* 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
*
* @param applicationContext 該bean所在的上下文(applicationContext、容器)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("call ApplicationContextAware.setApplicationContext()");
}
}
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.xsd">
<bean class="cn.ganlixin.entity.Student" id="student">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
<bean class="cn.ganlixin.entity.User" id="user">
<property name="id" value="88"/>
<property name="name" value="王五"/>
</bean>
<!-- 將實現了BeanPostProcessor接口的類也聲明為bean -->
<bean class="cn.ganlixin.processor.MyBeanPostProcessor"/>
</beans>
測試:
INFO [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName() INFO [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory() INFO [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext() INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student1, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student1, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:user, bean:User(id=88, name=王五) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:user, bean:User(id=88, name=王五) INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
從上面的運行結果可以得出以下結論:
1.因為只有Student實現了Aware接口,所以創建student bean的時候會調用對應的Aware接口方法,而User類沒有實現Aware接口,所以并沒有調用Aware接口方法;
2.Student和User類都沒有繼承BeanPostProcessor接口,但是在創建student和user bean的時候,都掉用了MyBeanPostProcessor類中的前置和后置處理(繼承自BeanPostProcessor接口);
3.BeanPostProcessor接口的前置和后置處理,是在Aware接口之后調用;
4.很重要的一點,需要將BeanPostProcessor接口實現類聲明為bean,使用<bean>配置或者使用@Component注解,不然BeanPostProcessor不起作用。
四.InitializingBean接口
創建Student類,實現InitializingBean接口,然后重寫afterPropertiesSet方法:
@Data
@Slf4j
public class Student implements InitializingBean {
private Integer id;
private String name;
@Override
public void afterPropertiesSet() throws Exception {
// 同樣可以在這里修改bean的屬性值
log.info("InitialingBean.afterPropertiesSet, this:{}", this);
}
}
修改xml配置文件,創建student bean,測試:
INFO [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
五.init-method
創建Student類,增加一個額外的方法display()
@Data
@Slf4j
public class Student {
private Integer id;
private String name;
public void display() {
log.info("Student.display call, this:{}", this);
}
}
修改配置文件,在<bean>標簽中增加init-method屬性,值為display,也就是Student的display方法名:
<?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.xsd">
<bean class="cn.ganlixin.entity.Student" id="student" init-method="display">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
</beans>
運行測試:
INFO [main] cn.ganlixin.entity.Student - Student.display call, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
上面,輸出了display中的內容,這是在設置bean的時候調用的。
六.DestructionAwareBeanPostProcessor接口
DestructionAwareBeanPostProcessor接口,從名稱上可以看出來是DestructionAware + BeanPostProcessor的組合,其實也的確是這樣,但是需要注意的就是,spring并沒有提供DestructionAware接口!!
下面是DestructionAwareBeanPostProcessor接口的定義:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* Destruction執行的操作
*
* @param bean 處理的bean
* @param beanName bean的名稱
* @throws BeansException
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* 是否需要執行postProcessBeforeDestruction方法
*
* @param bean 執行Destruction的bean
* @return 是否需要執行postProcessBeforeDestruction方法
*/
default boolean requiresDestruction(Object bean) {
return true;
}
}
DestructionAwareBeanPostProceesor繼承自BeanPostProcessor接口,所以也可以重寫前值和后置處理。
下面介紹使用示例,創建MyDestructionAwareBeanPostProceesor,繼承DestructionAwareBeanPostProceesor接口:
@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction,
beanName:{}, bean:{}", beanName, bean);
}
@Override
public boolean requiresDestruction(Object bean) {
return true; // 返回true,一律執行postProcessBeforeDestruction方法
// 如果返回false,則不執行postProcessBeforeDestruction方法
}
}
修改配置文件:
<?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.xsd">
<bean class="cn.ganlixin.entity.Student" id="student">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
<bean class="cn.ganlixin.entity.User" id="user">
<property name="id" value="88"/>
<property name="name" value="王五"/>
</bean>
<!-- 將實現了DestructionAwareBeanPostProcessor接口的實現類聲明為bean> -->
<bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/>
</beans>
測試程序:
@Slf4j
public class Test {
public static void main(String[] args) {
// 使用ApplicationContext來加載配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = context.getBean("student", Student.class);
User user = context.getBean("user", User.class);
log.info("測試程序獲取到的student bean:{}", student);
// 獲取bean工廠,然后調用destroyBean銷毀bean
AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
factory.destroyBean(student);
}
}
運行測試程序,輸出如下:
INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, beanName:cn.ganlixin.entity.Student, bean:Student(id=99, name=張三)
可以看到,在手動調用destroyBean方法來銷毀student bean的時候,調用了MyDestructionAwareBeanPostProcessor中定義的方法。
需要注意的是,雖然這里使用destroyBean來銷毀了student bean,如果又通過getBean來獲取student bean,則會重新創建student bean。
七.DisposableBean接口
前面介紹了DestructionAwareBeanPostProcessor接口,可以對所有的bean設置銷毀(destruction)后的處理操作。
而這里介紹的DisposableBean接口,就是對單獨的Bean進行destrction后的處理,也就是說不是應用到所有的bean上。
簡單介紹一下用法,創建Student類和User類,User類正常(不實現任何接口),Student類實現DisposableBean接口,然后重寫destroy方法:
@Data
@Slf4j
public class Student implements DisposableBean {
private Integer id;
private String name;
@Override
public void destroy() throws Exception {
log.info("DisposableBean.destroy, this:{}", this);
}
}
@Data
public class User {
private Integer id;
private String name;
}
創建配置文件:
<?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.xsd">
<bean class="cn.ganlixin.entity.Student" id="student">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
<bean class="cn.ganlixin.entity.User" id="user">
<property name="id" value="88"/>
<property name="name" value="王五"/>
</bean>
</beans>
測試程序:
@Slf4j
public class Test {
public static void main(String[] args) {
// 使用ApplicationContext來加載配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = context.getBean("student", Student.class);
User user = context.getBean("user", User.class);
log.info("測試程序獲取到的student bean:{}", student);
log.info("測試程序獲取到的user bean:{}",user);
// 獲取bean工廠,然后調用destroyBean銷毀bean
AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
factory.destroyBean(student);
factory.destroyBean(user);
}
}
運行輸出:
INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程序獲取到的user bean:User(id=88, name=王五) INFO [main] cn.ganlixin.entity.Student - DisposableBean.destroy, this:Student(id=99, name=張三)
可以看到,雖然測試代碼中destroy了student和user兩個bean,但是只有student bean在銷毀時觸發了DisposableBean的destory方法。
八.destroy-method方法
和init-method相對應的就是destory-method方法了,創建Student類,增加clean方法(自定義):
@Data
@Slf4j
public class Student {
private Integer id;
private String name;
public void clean() {
log.info("Student.clean, this:{}", this);
}
}
修改配置文件,<bean>標簽中使用destroy-method屬性,值為clean方法
<bean class="cn.ganlixin.entity.Student" id="student" destroy-method="clean">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
測試程序:
@Slf4j
public class Test {
public static void main(String[] args) {
// 使用ApplicationContext來加載配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = context.getBean("student", Student.class);
log.info("測試程序獲取到的student bean:{}", student);
// 刪除bean
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
registry.removeBeanDefinition("student");
}
}
輸出:
INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - Student.clean, this:Student(id=99, name=張三)
九.聲明周期大雜燴
上面對每一種接口都做了介紹,這里就將所有接口都做一下整合,嘗試在一個測試程序中測試所有接口,這個過程中就會對Bean的生命周期有清晰的認識:
9.1 實現多接口的Student類
創建Student類,實現Aware、InitializingBean、DisposableBean接口,并且增加display、clean方法,作為init-method和destory-method。
package cn.ganlixin.entity;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private Integer id;
private String name;
@Override
public void setBeanName(String s) {
log.info("BeanNameAware.setBeanName, this:{}", this);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("BeanFactoryAware.setBeanFactory, this:{}", this);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("ApplicationContextAware.setApplicationContext, this:{}", this);
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("InitialingBean.afterPropertiesSet, this:{}", this);
}
@Override
public void destroy() throws Exception {
log.info("DisposableBean.destory, this:{}", this);
}
public void display() {
log.info("init-method, Student.display, this:{}", this);
}
public void clean() {
log.info("destroy-method, Student.clean, this:{}", this);
}
}
9.2 BeanPostProcessor前后置處理
創建MyBeanPostProcessor接口實現類,并重寫前置和后置處理方法:
package cn.ganlixin.processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean);
return bean;
}
}
9.3 DestructionAwareBeanPostPrecessor接口
創建MyDestructionAwareBeanPostProcessor類,并重寫其中的方法(不重寫BeanPostProcessor的前后置處理方法):
package cn.ganlixin.processor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction,
beanName:{}, bean:{}", beanName, bean);
}
@Override
public boolean requiresDestruction(Object bean) {
return true; // 返回true,一律執行postProcessBeforeDestruction方法
// 如果返回false,則不執行postProcessBeforeDestruction方法
}
}
9.4 配置xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 創建student bean,指定init-method和destroy-method -->
<bean class="cn.ganlixin.entity.Student" id="student" init-method="display" destroy-method="clean">
<property name="id" value="99"/>
<property name="name" value="張三"/>
</bean>
<!-- 將實現了DestructionAwareBeanPostProcessor接口的實現類聲明為bean-->
<bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/>
<!-- 將實現了BeanPostProcessor接口的類也聲明為bean-->
<bean class="cn.ganlixin.processor.MyBeanPostProcessor"/>
</beans>
9.5 測試代碼
package cn.ganlixin;
import cn.ganlixin.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Slf4j
public class Test {
public static void main(String[] args) {
// 使用ApplicationContext來加載配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = context.getBean("student", Student.class);
log.info("測試程序獲取到的student bean:{}", student);
// 刪除bean
BeanDefinitionRegistry factory = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
factory.removeBeanDefinition("student");
}
}
9.6 輸出結果
INFO [main] cn.ganlixin.entity.Student - BeanNameAware.setBeanName, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - BeanFactoryAware.setBeanFactory, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - ApplicationContextAware.setApplicationContext, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - init-method, Student.display, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - DisposableBean.destory, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - destroy-method, Student.clean, this:Student(id=99, name=張三)
十.總結
看了上面這個輸出結果,再結合下面這個圖,基本就能掌握Bean的大致生命周期了。
原文地址:https://www.cnblogs.com/-beyond/p/13188675.html
總結
以上是生活随笔為你收集整理的Spring Bean生命周期的各阶段介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MyBatis源码分析-2-基础支持层-
- 下一篇: shell重启jar包