之前已經(jīng)就spring中的BeanPostProcessor使用方法以及其實(shí)現(xiàn)細(xì)節(jié)談?wù)撨^(guò),現(xiàn)在從更加宏觀、抽象的角度去理解spring的bpp具體是如何工作的,現(xiàn)在spring自身有多少bpp,如果我們有自定義的bpp需求,應(yīng)該如何實(shí)現(xiàn)。
其中如下demo的代碼位置 GitHub simple-spring
目錄
再談Spring BeanPostProcessor
1、BeanPostProcessor 種類
1.1、BeanPostProcessor 接口
1.2、InstantiationAwareBeanPostProcessor 接口
1.3、MergedBeanDefinitionPostProcessor 接口
2、源碼學(xué)習(xí)
2.1、實(shí)例化前的提前處理
2.2、實(shí)例化后的合并
2.3、實(shí)例化后的數(shù)據(jù)填充
2.4、初始化init方法
3、Demo
1、BeanPostProcessor 種類
如上圖,是在IDEA中使用control+H
命令顯示出來(lái)的BeanPostProcessor的繼承實(shí)現(xiàn)類關(guān)系圖,重點(diǎn)介紹BeanPostProcessor
,InstantiationAwareBeanPostProcessor
、MergedBeanDefinitionPostProcessor
三個(gè)接口,后面再繼續(xù)結(jié)合實(shí)際的實(shí)現(xiàn)類,分析spring是如何操作BeanPostProcessor對(duì)象的
閱讀這里面的源碼需要對(duì)Spring 源碼有一定的理解,具體的可看【目錄】Spring 源碼學(xué)習(xí)
1.1、BeanPostProcessor 接口
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 在調(diào)用bean的init方法(非構(gòu)造方法)前調(diào)用
// beanName 是在Spring IOC 容器的bean 名稱,返回的對(duì)象需要會(huì)被直接使用
// 切記!!!默認(rèn)返回bean即可,不要無(wú)緣無(wú)故返回null,會(huì)出現(xiàn)各種NPE的情況
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
// 在調(diào)用bean的init方法(非構(gòu)造方法)后調(diào)用
}
1.2、InstantiationAwareBeanPostProcessor 接口
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
// 在對(duì)象實(shí)例化之前被調(diào)用,傳入的參數(shù)是類型以及bean的那么
// 如果有返回非空的對(duì)象,則意味著不需要調(diào)用doCreate操作完成對(duì)象實(shí)例化等
// 同時(shí)返回非空后會(huì)調(diào)用postProcessAfterInitialization方法
// 注意看,不是postProcessAfterInstantiation而是postProcessAfterInitialization方法
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
// 返回的是boolean類型,并不是和postProcessBeforeInstantiation配套使用的,在正常的實(shí)例化之后
// 主要功能是判斷是否需要完成對(duì)象填充
// 如果返回false,則意味著不會(huì)完成對(duì)象屬性的填充,例如@Resource導(dǎo)入的對(duì)象還是為null
PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
// 提供給已經(jīng)實(shí)例化的對(duì)象一種可以自定義完成對(duì)象pv屬性的修改操作
// 注意不要隨意返回null,一旦返回null,不會(huì)進(jìn)行對(duì)象填充、對(duì)象依賴等操作
}
1.3、MergedBeanDefinitionPostProcessor 接口
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
// 在完成bean的實(shí)例化之后,填充數(shù)據(jù)(populateBean)之前,可自定義的修改beanDefinition內(nèi)容
// 名字成為merge,合并BPP對(duì)象和對(duì)于的beanDefinition的內(nèi)容
// 實(shí)際上可以完成任何想任何實(shí)現(xiàn)的功能
}
以上的三個(gè)接口基本上能夠覆蓋所有的BPP特定的功能點(diǎn),從上面圖也可以看出來(lái),spring、springboot很多模塊都有相應(yīng)的對(duì)象實(shí)現(xiàn),完成特定的功能。
2、源碼學(xué)習(xí)
2.1、實(shí)例化前的提前處理
直接定位到AbstractAutowireCapableBeanFactory類的createBean方法,主要介紹的是InstantiationAwareBeanPostProcessor
try {
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
// 如果bean有用,則會(huì)直接返回,不會(huì)再繼續(xù)執(zhí)行doCreateBean方法
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
// bean創(chuàng)建失敗,在初始化之前錯(cuò)誤了
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 如果存在InstantiationAwareBeanPostProcessor對(duì)象
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
// 調(diào)用的是postProcessBeforeInstantiation方法
if (bean != null) {
// 如果返回的數(shù)據(jù)不為null,則調(diào)用的是postProcessAfterInitialization方法
// 注意別看錯(cuò)了,一個(gè)是實(shí)例化Instantiation,一個(gè)是初始化Initialization
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
// 記錄下是否通過(guò)提前批次的處理(如果bean不為null,則肯定是)
}
// 最后返回結(jié)果
return bean;
}
其意思就是利用在實(shí)例化之前檢查是否存在合適的InstantiationAwareBeanPostProcessor對(duì)象,去攔截某些需要被處理的bean提前完成bean的實(shí)例化過(guò)程,不會(huì)去調(diào)用init方法,也沒(méi)有數(shù)據(jù)的填充,@Resource對(duì)象的引入等操作。
2.2、實(shí)例化后的合并
實(shí)例化后,僅僅是完成了對(duì)象最基礎(chǔ)的實(shí)例化工作,還未涉及到填充數(shù)據(jù),init方法執(zhí)行等操作,主要介紹的是MergedBeanDefinitionPostProcessor
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 合并管理bean
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
// 遍歷所有的BeanPostProcessor
// 篩選出屬于MergedBeanDefinitionPostProcessor的對(duì)象,調(diào)用postProcessMergedBeanDefinition
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
2.3、實(shí)例化后的數(shù)據(jù)填充
主要的操作在populateBean方法中,涉及到的也是InstantiationAwareBeanPostProcessor
再次強(qiáng)調(diào)InstantiationAwareBeanPostProcessor接口不僅僅是用在實(shí)例化前,在實(shí)例化之后也同樣有用
boolean continueWithPropertyPopulation = true;
// 設(shè)置可以繼續(xù)設(shè)置pv值的boolean對(duì)象為true
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 如果是InstantiationAwareBeanPostProcessor對(duì)象
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 調(diào)用postProcessAfterInstantiation
// 如果返回false意味著不需要填充pv操作了,直接break
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
// 上文設(shè)置為false后,直接返回,完全忽略后續(xù)的applyPropertyValues操作
return;
}
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
// 對(duì)bean對(duì)象的pv值進(jìn)行處理操作
if (pvs == null) {
// 如果返回為null,則直接返回
// 所以在自定義設(shè)置BPP的時(shí)候必須注意該方法的返回值
// 通過(guò)ide自動(dòng)生成的對(duì)象,其默認(rèn)返回值是null
return;
}
}
}
}
if (needsDepCheck) {
// 檢查對(duì)象的依賴問(wèn)題
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
2.4、初始化init方法
在spring中是可以設(shè)置對(duì)象的init方法,在對(duì)象實(shí)現(xiàn)之后,在initializeBean方法中,如下的代碼片段
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 調(diào)用postProcessBeforeInitialization
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
// 動(dòng)態(tài)代理反射invoke調(diào)用初始化方法
// 就是在這里獲取到bean的init方法調(diào)用信息,invoke調(diào)用
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
// 唯一一個(gè)被調(diào)用了2次的地方的方法postProcessAfterInitialization
}
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
// 都有個(gè)這樣的操作,返回為null,則退出
return result;
}
}
return result;
}
3、Demo
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("student")) {
Student student = new Student("bpp", 20);
return student;
}
if (beanName.equals("superStudent")) {
SuperStudent studentAndTeacher = new SuperStudent();
studentAndTeacher.setName("zhangsan");
return studentAndTeacher;
}
return null;
}
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//return pvs;
return null;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
public class SuperStudent {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Resource
private Teacher teacher;
public void doInit() {
System.out.println("superstudent init");
}
public void doSet() {
if (teacher != null) {
teacher.setAge(19);
teacher.setName("superStudent");
System.out.println(teacher.toString());
} else {
System.out.println("teacher is null");
}
}
@Override
public String toString() {
return "SuperStudent{" +
"name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
public static void runBPP() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
new String[]{"context-bpp.xml"});
SuperStudent student = (SuperStudent) applicationContext.getBean("superStudent");
Teacher teacher = (Teacher) applicationContext.getBean("teacher");
System.out.println(teacher.toString());
System.out.println(student.toString());
student.doSet();
System.out.println(teacher.toString());
}
如下圖幾種樣例的代碼
-
返回pv為null
image
很清楚在SuperStudent的對(duì)象是null,并沒(méi)有完成填充操作,但是調(diào)用了init方法
-
返回pv為原值,不作任何改變
image
完成了填充操作,而且這個(gè)SuperStudent的teacher對(duì)象是和Spring IOC 容器內(nèi)的保持一致
-
設(shè)置postProcessBeforeInstantiation
image
SuperStudent返回輸出的對(duì)象,teacher沒(méi)有值,而且也沒(méi)有調(diào)用其init的方法