在此係列文章中,我總結了Spring幾乎所有的擴充套件介面,以及各個擴充套件點的使用場景。並整理出一個bean在spring中從被載入到最終初始化的所有可擴充套件點的順序呼叫圖。這樣,我們也可以看到bean是如何一步步載入到spring容器中的。
InstantiationAwareBeanPostProcessor
1、概述
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { @Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { return null; } }
Spring框架提供了許多擴充套件介面,用於在Bean的生命週期中插入自定義邏輯。其中之一是InstantiationAwareBeanPostProcessor介面,它允許我們在Spring容器例項化Bean之前和之後進行一些自定義處理。
InstantiationAwareBeanPostProcessor介面是BeanPostProcessor介面的子介面,它定義了在Bean例項化過程中的擴充套件點。與BeanPostProcessor介面相比,InstantiationAwareBeanPostProcessor介面提供了更細粒度的控制能力。它在Bean例項化的不同階段提供了多個回撥方法,允許我們在不同的時機對Bean進行自定義處理。
在Spring容器啟動過程中,InstantiationAwareBeanPostProcessor介面的方法執行順序如下:
- postProcessBeforeInstantiation方法:在Bean例項化之前呼叫,如果返回null,一切按照正常順序執行,如果返回的是一個例項的物件,那麼這個將會跳過例項化、初始化的過程
- postProcessAfterInstantiation方法:在Bean例項化之後呼叫,可以對已例項化的Bean進行進一步的自定義處理。
- postProcessPropertyValues方法:在Bean的屬性注入之前呼叫,可以修改Bean的屬性值或進行其他自定義操作,當postProcessAfterInstantiation返回true才執行。
方法 | 執行順序 | 備註 |
---|---|---|
postProcessBeforeInstantiation() | 在 Bean 建立前呼叫 | 可用於建立代理類,如果返回的不是 null(也就是返回的是一個代理類) ,那麼後續只會呼叫 postProcessAfterInitialization() 方法 |
postProcessAfterInstantiation() | 在 Bean 建立後呼叫 | 返回值會影響 postProcessProperties() 是否執行,其中返回 false 的話,是不會執行。 |
postProcessProperties() | 在 Bean 設定屬性前呼叫 | 用於修改 bean 的屬性,如果返回值不為空,那麼會更改指定欄位的值 |
2、簡單案例
下面是一個示例,演示了TestUser這個Bean內部的執行流程。
// InstantiationAwareBeanPostProcessor擴充套件實現
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(isMatchClass(beanClass)){
System.out.println("呼叫 postProcessBeforeInstantiation 方法");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(isMatchClass(bean.getClass())){
System.out.println("呼叫 postProcessAfterInstantiation 方法");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if(isMatchClass(bean.getClass())){
System.out.println("呼叫 postProcessProperties 方法");
}
return pvs;
}
private boolean isMatchClass(Class<?> beanClass){
return TestUser.class.equals(ClassUtils.getUserClass(beanClass));
}
}
// TestUser測試類
@Component
public class TestUser implements InitializingBean {
String name;
String password;
public TestUser() {
System.out.println("建立【TestUser】物件");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("設定【name】屬性");
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println("設定【password】屬性");
this.password = password;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("所有屬性設定完畢");
}
}
輸出:
呼叫 postProcessBeforeInstantiation 方法
建立【TestUser】物件
呼叫 postProcessAfterInstantiation 方法
呼叫 postProcessProperties 方法
所有屬性設定完畢
3、原始碼分析
InstantiationAwareBeanPostProcessor是在物件例項化和初始化前後執行的邏輯,因此主要的程式碼都在getBean,doGetBean,cerateBean方法中。
- 在MyBeanFactoryPostProcessor打上斷點,啟動SpringApplication,可以看到左下角的呼叫鏈路。
- spring的AbstractApplicationContext的refresh方法,執行this.onRefresh()。
- 在例項化之前,呼叫postProcessBeforeInstantiation方法入口就在this.resolveBeforeInstantiation(beanName, mbdToUse)中。
- bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)中遍歷InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法。
- 若 this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)返回了已例項化的Bean,則執行呼叫postProcessAfterInitialization方法。
- 在執行完resolveBeforeInstantiation()後,呼叫doCreateBean()。
- 在doCreateBean()中先例項化Bean,再呼叫populateBean()執行後續的postProcessAfterInstantiation()和postProcessProperties()。