文章目錄
- 夯實Spring系列|第十四章:Spring Bean 生命週期-下篇
- 本章說明
- 1.項目環境
- 2.Spring Bean Aware 接口回調階段
- 3.Spring Bean 初始化前階段
- 4.Spring Bean 初始化階段
- 5.Spring Bean 初始化後階段
- 6.Spring Bean 初始化完成階段
- 7.Spring Bean 銷燬前階段
- 8.Spring Bean 銷燬階段
- 9.Spring Bean 垃圾收集
- 10.面試題
- 10.1 BeanPostProcessor 的使用場景有哪些?
- 10.2 BeanFactoryPostProcessor 與 BeanPostProcessor 的區別?
- 10.3 BeanFactory 是怎樣處理 Bean 生命週期?
- 11.參考
夯實Spring系列|第十四章:Spring Bean 生命週期-下篇
本章說明
本文是 Spring Bean 生命週期系列的最後一篇,會對 Spring Bean 初始化階段以及後面的銷燬階段進行分析和討論。Aware 回調源碼其實是在 initializeBean 方法中 (初始化 Bean 階段),所以也可以當成是 Spring Bean 初始化階段。
1.項目環境
- jdk 1.8
- spring 5.2.2.RELEASE
- github 地址:https://github.com/huajiexiewenfeng/thinking-in-spring
- 本章模塊:bean-lifecycle
2.Spring Bean Aware 接口回調階段
Spring Aware 接口(此接口順序也是源碼的回調執行順序)
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- EnvironmentAware
- EmbeddedValueResovlerAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ApplicationContextAware
2.1 示例改造1
UserHolder 分別實現 BeanNameAware, BeanClassLoaderAware, BeanFactoryAware 三個回調接口
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
private User user;
private Integer number;
private String description;
public UserHolder(User user) {
this.user = user;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "UserHolder{" +
"user=" + user +
", number=" + number +
", description='" + description + '\'' +
", beanName='" + beanName + '\'' +
'}';
}
private ClassLoader classLoader;
private BeanFactory beanFactory;
private String beanName;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
使用之前的 BeanInstantiationLifecycleDemo 示例代碼,執行結果
UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder'}
2.2 源碼分析1
AbstractAutowireCapableBeanFactory#doCreateBean 595 行,同樣還是 doCreateBean 方法,但是之前是屬性賦值階段 populateBean,現在是 initializeBean 階段。
繼續往下
源碼位置 AbstractAutowireCapableBeanFactory#invokeAwareMethods,通過源碼我們可以看到分別對 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 進行判斷。
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
2.3 ApplicationContext 生命週期 Aware 回調
繼續改造上面的示例
UserHolder,我們再實現一個 EnvironmentAware 回調
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware {
private User user;
private Integer number;
private String description;
public UserHolder(User user) {
this.user = user;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "UserHolder{" +
"user=" + user +
", number=" + number +
", description='" + description + '\'' +
", beanName='" + beanName + '\'' +
", environment=" + environment +
'}';
}
private ClassLoader classLoader;
private BeanFactory beanFactory;
private String beanName;
private Environment environment;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
執行結果:
UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=null}
可以看到 environment=null,setEnvironment() 打上斷點,也不會執行,說明 EnvironmentAware 沒有被回調。
其實原因是這些 Aware 回調接口是 ApplicationContext 生命週期中的,並不在 BeanFactory 生命週期中,這是 BeanFactory 和 ApplicationContext 的一個具體區別之一。
2.4 示例改造2
所以我們這裏需要再對示例代碼進行改造觸發 ApplicationContext 生命週期中
/**
* Bean 實例化生命週期
*/
public class BeanInstantiationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
System.out.println("------------------");
executeApplicationContext();
}
private static void executeApplicationContext(){
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(locations);
//第一種添加 BeanpostBeanProcess 實現方式:
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//第二種添加 BeanpostBeanProcess 實現方式:
//將 <bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/> 配置在 xml 中
applicationContext.refresh();
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
applicationContext.close();
}
private static void executeBeanFactory(){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//內部類 無法添加 ApplicationContextAwareProcessor
// beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(beanFactory));
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
// System.out.println("Bean 定義的數量: " + count);
// String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
// Stream.of(beanDefinitionNames).forEach(System.out::println);
User user = beanFactory.getBean("user", User.class);
SuperUser superUser = beanFactory.getBean("superUser", SuperUser.class);
// 構造器注入是按照類型注入,resolveDependency
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
}
將 MyInstantiationAwareBeanPostProcess 獨立成一個單獨的類,不在作爲內部類
bean-constructor-injection.xml 加入 MyInstantiationAwareBeanPostProcess 配置
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/>
<bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
autowire="constructor">
<!--<property name="number" value="1"/>-->
<property name="description" value="The user holder" />
</bean>
</beans>
執行結果:
UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=null}
------------------
UserHolder{user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}, number=1, description='The user holder v2', beanName='userHolder', environment=StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[PropertiesPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}]}}
可以看到 BeanFactory 的方式無法回調 EnvironmentAware,而 ApplicationContext 可以。
2.5 源碼分析2
我們看一下 AbstractApplicationContext#prepareBeanFactory 中如何進行 Aware 回調
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
...
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
關鍵代碼 ApplicationContextAwareProcessor 我們再看下 ApplicationContextAwareProcessor 具體實現
ApplicationContextAwareProcessor#invokeAwareInterfaces
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
代碼和 BeanNameAware 的回調如出一轍。
3.Spring Bean 初始化前階段
初始化前階段已完成以下三個階段
- Bean 實例化
- Bean 屬性賦值
- Bean Aware 接口回調
方法回調
- BeanPostProcessor#postProcessBeforeInitialization
3.1 示例代碼
爲了打印方便我們可以把 UserHolder#toString 方法改造一下
@Override
public String toString() {
return "UserHolder{" +
"number=" + number +
", description='" + description +
", user=" + user +
'}';
}
MyInstantiationAwareBeanPostProcess 新增 postProcessBeforeInitialization 的實現
public class MyInstantiationAwareBeanPostProcess implements InstantiationAwareBeanPostProcessor {
/**
* 實例化前階段
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "superUser") && SuperUser.class.equals(beanClass)) {
SuperUser user = new SuperUser();
user.setName("new-superUser v1");
return user;
}
return null;
}
/**
* 實例化後階段
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "user") && User.class.equals(bean.getClass())) {
//"user" 對象不允許屬性賦值(配置元信息-> 屬性值)
User user = User.class.cast(bean);
user.setId(2L);
user.setName("after-superUser v2");
return false;//返回 false 表示忽略掉配置元信息,比如 <bean ...<property name = id value = 1/>
}
return true;
}
// user 跳過 Bean 屬性賦值
// superUser 也是完全跳過 Bean 實例化
// 這裏我們只能攔截 UserHolder
/**
* 屬性賦值前階段
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
final MutablePropertyValues propertyValues;
// 兼容 pvs 爲空的情況 pvs 對應xml中配置的 <property .../>
if (pvs instanceof MutablePropertyValues) {
propertyValues = (MutablePropertyValues) pvs;
} else {
propertyValues = new MutablePropertyValues();
}
// 此操作等價於 <property name="number" value="1"/>
propertyValues.addPropertyValue("number", "1");
if (propertyValues.contains("description")) {
// PropertyValue 無法直接覆蓋,因爲是 final 類型
PropertyValue description = propertyValues.getPropertyValue("description");
propertyValues.removePropertyValue("description");
propertyValues.addPropertyValue("description", "The user holder v2");
System.out.println("屬性賦值前階段 : postProcessProperties() -> The user holder v2");
}
return propertyValues;
}
return null;
}
/**
* 初始化前階段
* 這個接口實際上是覆蓋的 BeanPostProcessor 中的方法
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
UserHolder user = UserHolder.class.cast(bean);
user.setDescription("The user holder v3");
System.out.println("初始化前階段 : postProcessBeforeInitialization() -> The user holder v3");
}
return bean;
}
}
調用示例 BeanInitializationLifecycleDemo
/**
* Bean 初始化生命週期
*/
public class BeanInitializationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
}
private static void executeBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
}
執行結果:
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
UserHolder{number=1, description='The user holder v3, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
3.2 源碼分析
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 同樣也是遍歷我們所有的 BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 執行 postProcessBeforeInitialization 獲取返回結果 如果爲 null 就返回當前 bean
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
4.Spring Bean 初始化階段
Bean 初始化(Initialization)
- @PostConstruct 標註方法
- 實現 InitializingBean 接口的 afterPropertiesSet() 方法
- 自定義初始化方法
4.1 示例改造
UserHolder 我們分別加入三種初始化的方式,需要注意的是 @PostConstruct 是 Java 通用註解,需要特殊的方式進行觸發,相關文章 第九章:IoC 依賴注入(專題)-下 10.Java 通用注入原理 小節
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean {
private User user;
private Integer number;
private String description;
public UserHolder(User user) {
this.user = user;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@PostConstruct
public void init(){
this.description = "The userHolder v4";
System.out.println("初始化階段 : @PostConstruct -> The user holder v4");
}
@Override
public void afterPropertiesSet() throws Exception {
this.description = "The userHolder v5";
System.out.println("初始化階段 : afterPropertiesSet() -> The user holder v5");
}
public void customInit() throws Exception {
this.description = "The userHolder v6";
System.out.println("初始化階段 : customInit() -> The user holder v6");
}
@Override
public String toString() {
return "UserHolder{" +
"number=" + number +
", description='" + description +
", user=" + user +
'}';
}
private ClassLoader classLoader;
private BeanFactory beanFactory;
private String beanName;
private Environment environment;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
bean-constructor-injection.xml 文件 bean 增加 init-method=“customInit” 屬性
<bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
autowire="constructor" init-method="customInit">
<!--<property name="number" value="1"/>-->
<property name="description" value="The user holder" />
</bean>
調用示例 BeanInitializationLifecycleDemo
/**
* Bean 初始化生命週期
*/
public class BeanInitializationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
}
private static void executeBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
}
執行結果:
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
UserHolder{number=1, description='The userHolder v6, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
4.2 源碼分析
從源碼可以很清晰的看到 初始化前 -> 初始化 -> 初始化後 三個階段
過程相對簡單,這裏就不一 一截圖演示了,可對照源碼位置打上斷點進行調試:
- afterPropertiesSet
AbstractAutowireCapableBeanFactory#invokeInitMethods 1855 行
((InitializingBean) bean).afterPropertiesSet();
- 自定義方法
AbstractAutowireCapableBeanFactory#invokeInitMethods 1864 行
invokeCustomInitMethod(beanName, bean, mbd);
- @PostContruct
其實在初始化前的操作中就已經完成了 postProcessBeforeInitialization
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata#invokeInitMethods 333 行
5.Spring Bean 初始化後階段
方法回調
- BeanPostProcessor#postProcessAfterInitialization
5.1 示例改造
和初始化前的階段一樣,我們只需要重寫 BeanPostProcessor 中的 postProcessAfterInitialization 方法即可
public class MyInstantiationAwareBeanPostProcess implements InstantiationAwareBeanPostProcessor {
... //省略掉之前的階段代碼
/**
* 初始化後階段
* 這個接口實際上是覆蓋的 BeanPostProcessor 中的方法
*/
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
UserHolder user = UserHolder.class.cast(bean);
user.setDescription("The user holder v7");
System.out.println("初始化後階段 : postProcessAfterInitialization() -> The user holder v7");
}
return bean;
}
}
執行結果:
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
UserHolder{number=1, description='The user holder v7, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
5.2 源碼分析
這個源代碼和初始化前階段的 applyBeanPostProcessorsBeforeInitialization 源碼基本上完全一樣
- 遍歷所有的 BeanPostProcessor 執行 postProcessAfterInitialization 方法
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
5.3 小結
從上面源碼分析可以看出 initializeBean 初始化 Bean 的方法依次進行了四個操作
- invokeAwareMethods(beanName, bean); //Aware回調
- applyBeanPostProcessorsBeforeInitialization //初始化前
- invokeInitMethods //初始化
- applyBeanPostProcessorsAfterInitialization //初始化後
6.Spring Bean 初始化完成階段
方法回調
- Spring 4.1+: SmartInitializingSingleton#afterSingletonsInstantiated
6.1 示例改造
UserHolder 實現 SmartInitializingSingleton 接口
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean,SmartInitializingSingleton {
private User user;
private Integer number;
private String description;
public UserHolder(User user) {
this.user = user;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@PostConstruct
public void init(){
this.description = "The userHolder v4";
System.out.println("初始化階段 : @PostConstruct -> The user holder v4");
}
@Override
public void afterPropertiesSet() throws Exception {
this.description = "The userHolder v5";
System.out.println("初始化階段 : afterPropertiesSet() -> The user holder v5");
}
public void customInit() throws Exception {
this.description = "The userHolder v6";
System.out.println("初始化階段 : customInit() -> The user holder v6");
}
@Override
public String toString() {
return "UserHolder{" +
"number=" + number +
", description='" + description +
", user=" + user +
'}';
}
private ClassLoader classLoader;
private BeanFactory beanFactory;
private String beanName;
private Environment environment;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void afterSingletonsInstantiated() {
this.description = "The userHolder v8";
System.out.println("初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8");
}
}
afterSingletonsInstantiated 這個方法此時還不能被回調,我們需要通過 Idea 來查找這個方法在哪裏被調用過,
DefaultListableBeanFactory#preInstantiateSingletons,所以我們需要在代碼中顯示的調用這個方法
beanFactory.preInstantiateSingletons();
/**
* Bean 初始化生命週期
*/
public class BeanInitializationLifecycleDemo {
public static void main(String[] args) {
executeBeanFactory();
}
private static void executeBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
// 通常在 ApplicationContext 場景使用
beanFactory.preInstantiateSingletons();
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
System.out.println(userHolder);
}
}
執行結果:
user用戶對象初始化...
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
UserHolder{number=1, description='The userHolder v8, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
6.2 備註
SmartInitializingSingleton 通常在 ApplicationContext 場景使用,因爲在應用上下文啓動過程中,AbstractApplicationContext#refresh 中 finishBeanFactoryInitialization(beanFactory);
會顯示的調用這個 preInstantiateSingletons() 方法。
preInstantiateSingletons 在 AbstractApplicationContext 場景非常重要,有兩層含義
- 初始化我們所有的 Spring Bean
- 通過 beanDefinitionNames 來遍歷我們所有的 BeanDefintion,逐一進行 getBean(beanName) 操作,通過我們的 BeanDefinition 創建 bean 對象,並緩存到 DefaultSingletonBeanRegistry#singletonObjects 中
- 當我們的 Spring Bean 全部初始化完成之後,再進行 afterSingletonsInstantiated() 方法的回調
7.Spring Bean 銷燬前階段
方法回調
- DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
7.1 示例代碼
新增 MyDestructionAwareBeanPostProcessor 實現 DestructionAwareBeanPostProcessor
覆蓋 postProcessBeforeDestruction 銷燬前的方法
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (ObjectUtils.nullSafeEquals(beanName, "userHolder") && UserHolder.class.equals(bean.getClass())) {
UserHolder user = UserHolder.class.cast(bean);
user.setDescription("The user holder v9");
System.out.println("銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9");
}
}
}
調用需要的執行 beanFactory.destroyBean("userHolder",userHolder);
銷燬這個 bean 纔會觸發銷燬前的過程。
/**
* Bean 完整生命週期
*/
public class BeanLifecycleDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
// 添加 DestructionAwareBeanPostProcessor 銷燬前
beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
beanFactory.preInstantiateSingletons();
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
beanFactory.destroyBean("userHolder",userHolder);
System.out.println(userHolder);
}
}
執行結果:
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
UserHolder{number=1, description='The user holder v9, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
7.2 源碼調試
org.springframework.beans.factory.support.DisposableBeanAdapter#destroy
循環遍歷 beanPostProcessors,執行 postProcessBeforeDestruction 方法
8.Spring Bean 銷燬階段
Bean 銷燬(Destroy)
- @PreDestroy 標註方法
- 實現 DisposableBean 接口的 destroy() 方法
- 自定義銷燬方法
8.1 示例方法
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean,SmartInitializingSingleton, DisposableBean {
...//省略掉其他重複代碼
@PreDestroy
public void preDestroy(){
this.description = "The userHolder v10";
System.out.println("銷燬階段 : @PreDestroy -> The user holder v10");
}
@Override
public void destroy() throws Exception {
this.description = "The userHolder v11";
System.out.println("初始化階段 : DisposableBean#destroy -> The user holder v11");
}
public void customDestroy(){
this.description = "The userHolder v12";
System.out.println("初始化階段 : customDestroy -> The user holder v12");
}
}
bean-constructor-injection.xml 增加 destroy-method="customDestroy"
屬性
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="com.huajie.thinking.in.spring.bean.lifecycle.MyInstantiationAwareBeanPostProcess"/>
<bean id="userHolder" class="com.huajie.thinking.in.spring.bean.lifecycle.domain.UserHolder"
autowire="constructor" init-method="customInit" destroy-method="customDestroy">
<!--<property name="number" value="1"/>-->
<property name="description" value="The user holder" />
</bean>
</beans>
調用示例,注意 DestructionAwareBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 的添加順序,因爲 @PostConstruct、@PreDestroy 由 CommonAnnotationBeanPostProcessor 觸發,但是 BeanPostProcessor 的添加是 FIFO 的模式,所以 DestructionAwareBeanPostProcessor 必須在之前進行添加。
/**
* Bean 完整生命週期
*/
public class BeanLifecycleDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//添加 DestructionAwareBeanPostProcessor 銷燬前
beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
//添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
beanFactory.preInstantiateSingletons();
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
beanFactory.destroyBean("userHolder",userHolder);
System.out.println(userHolder);
}
}
執行結果:
屬性賦值前階段 : postProcessProperties() -> The user holder v2
Disconnected from the target VM, address: '127.0.0.1:51595', transport: 'socket'
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
銷燬階段 : @PreDestroy -> The user holder v10
初始化階段 : DisposableBean#destroy -> The user holder v11
初始化階段 : customDestroy -> The user holder v12
UserHolder{number=1, description='The userHolder v12, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
8.2 源碼調試
DisposableBeanAdapter#destroy 242 行,可以看到有兩個 beanPostProcessor,分別是我們添加的 DestructionAwareBeanPostProcessor、CommonAnnotationBeanPostProcessor
1.DestructionAwareBeanPostProcessor 執行銷燬前的方法
2.CommonAnnotationBeanPostProcessor 觸發 @PreDestroy 銷燬方法
258 行,執行 DisposableBean#destroy 方法
273 行,執行我們自定義的方法 customDestroy
9.Spring Bean 垃圾收集
Bean 垃圾回收
- 關閉 Spring 容器(應用上下文)
- 執行 GC
- Spring Bean 覆蓋 finalize() 方法被回調
9.1 示例改造
UserHolder 覆蓋 Object#finalize 方法,因爲這個方法會在對象被 GC 的時候調用
public class UserHolder implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, InitializingBean, SmartInitializingSingleton, DisposableBean {
...//省略重複代碼
@Override
public void finalize() throws Throwable {
System.out.println(beanName + " 被垃圾回收");
}
}
調用示例中添加
- beanFactory.destroySingletons();//銷燬掉所有單例對象,保證沒有對象的強引用,導致無法 gc
- userHolder=null;//對象置爲空
- System.gc(); //調用 Full gc
/**
* Bean 完整生命週期
*/
public class BeanLifecycleDemo {
public static void main(String[] args) throws InterruptedException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//添加 BeanpostBeanProcess 實現
beanFactory.addBeanPostProcessor(new MyInstantiationAwareBeanPostProcess());
//添加 DestructionAwareBeanPostProcessor 銷燬前
beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
//添加 CommonAnnotationBeanPostProcessor 觸發 @PostConstruct
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
String[] locations = {"classpath:/META-INF/dependency-lookup-context.xml", "classpath:/META-INF/bean-constructor-injection.xml"};
int count = reader.loadBeanDefinitions(locations);
beanFactory.preInstantiateSingletons();
UserHolder userHolder = beanFactory.getBean("userHolder", UserHolder.class);
// beanFactory.destroyBean("userHolder",userHolder);
beanFactory.destroySingletons();
System.out.println(userHolder);
userHolder=null;
System.gc();
Thread.sleep(5000);
}
}
執行結果:
user用戶對象初始化...
屬性賦值前階段 : postProcessProperties() -> The user holder v2
初始化前階段 : postProcessBeforeInitialization() -> The user holder v3
初始化階段 : @PostConstruct -> The user holder v4
初始化階段 : afterPropertiesSet() -> The user holder v5
初始化階段 : customInit() -> The user holder v6
初始化後階段 : postProcessAfterInitialization() -> The user holder v7
初始化完成階段 : afterSingletonsInstantiated() -> The user holder v8
銷燬前階段 : postProcessBeforeDestruction() -> The user holder v9
銷燬階段 : @PreDestroy -> The user holder v10
初始化階段 : DisposableBean#destroy -> The user holder v11
初始化階段 : customDestroy -> The user holder v12
user用戶對象銷燬...
UserHolder{number=1, description='The userHolder v12, user=SuperUser{address='null'}User{beanName='null', id=null, name='new-superUser v1', age=null, configFileReource=null, city=null, cities=null, lifeCities=null}}
userHolder 被垃圾回收
10.面試題
10.1 BeanPostProcessor 的使用場景有哪些?
BeanPostProcessor 提供 Spring Bean 初始化前和初始化後的生命週期回調,分別對應 postProcessBeforelnitialization 以及 pistProcessAfterInitialization 方法,允許對相關的 Bean 進行擴展,甚至是替換。
BeanPostProcessor 的子類 DestructionAwareBeanPostProcessor 提供銷燬前的生命週期回調。
BeanPostProcessor 的子類 InstantiationAwareBeanPostProcessor 提供實例化前postProcessBeforeInstantiation,實例化後 postProcessAfterInstantiation,屬性賦值前 postProcessProperties 的生命週期回調。
加分項:其中 ApplicationContext 相關的 Aware 回調也是基於 BeanPostProcessor 實現,即 ApplicationContextAwareProcessor。
10.2 BeanFactoryPostProcessor 與 BeanPostProcessor 的區別?
其實兩者無法進行對比,BeanFactoryPostProcessor 是 Spring BeanFactory(實際是ConfigurableListableBeanFactory)的後置處理器,用於擴展 BeanFactory,或者通過 BeanFactory 進行依賴查找和依賴注入。
而 BeanPostProcessor 則是直接與 BeanFactory 關聯,屬於 N 對 1 的關係。
加分項:BeanFactoryPostProcessor 必須有 Spring ApplicationContext 執行,BeanFactory 無法直接與其交互。
10.3 BeanFactory 是怎樣處理 Bean 生命週期?
BeanFactory 的默認實現爲 DefaultListableBeanFactory ,其中 Bean 生命週期與方法映射如下:
-
BeanDefinition 註冊階段 - registerBeanDefinition
-
BeanDefinition 合併階段 - getMergedBeanDefinition
-
Bean 實例化前階段 - resolveBeforeInstantiation
-
Bean 實例化階段 - createBeanInstance
-
Bean 實例化後階段 - populateBean
-
Bean 屬性賦值前階段 - populateBean
-
Bean 屬性賦值階段 - populateBean
-
Bean Aware 接口回調階段 - initializeBean
-
Bean 初始化前階段 - initializeBean
-
Bean 初始化階段 - initializeBean
-
Bean 初始化後階段 - initializeBean
-
Bean 初始化完成階段 - preInstantiateSingletons
-
Bean 銷燬前階段 - destroyBean
-
Bean 銷燬階段 - destroyBean
11.參考
- 極客時間-小馬哥《小馬哥講Spring核心編程思想》