淺談Spring中幾個(gè)PostProcessor的區(qū)別與聯(lián)系
Spring幾個(gè)PostProcessor的區(qū)別
首先明確 Bean 的生命周期:
- 首先注冊(cè) Bean 的定義信息;
- 然后創(chuàng)建 Bean 的實(shí)例;
- 最后初始化 Bean ,放入容器中。
按照?qǐng)?zhí)行的順序,可以分為以下幾個(gè)步驟:
BeanDefinitionRegistryPostProcessor 是在注冊(cè) Bean 定義信息前后調(diào)用;
BeanFactoryPostProcessor 是在創(chuàng)建 Bean 前后調(diào)用;
BeanPostProcessor 是在初始化 Bean 前后調(diào)用;
其中 BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子類,所以可以使用前者代替后者實(shí)現(xiàn)功能。
查看 IOC 容器創(chuàng)建時(shí)的調(diào)用流程
refresh 方法的代碼如下:
// Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh();
其中的 invokeBeanFactoryPostProcessors 就執(zhí)行了注冊(cè)定義信息和創(chuàng)建 Bean 的方法;而 finishBeanFactoryInitialization 執(zhí)行了初始化 Bean 的方法。
具體的執(zhí)行順序大家可以自行打斷點(diǎn)調(diào)試,由于涉及的源碼過多,這里不再展示。
spring-postProcessor的執(zhí)行時(shí)機(jī)
spring bean 的生命周期粗糙的分為以下步驟。
實(shí)例化(創(chuàng)建一個(gè)屬性都為空的對(duì)象)---------》屬性填充(populateBean,下文中這個(gè)步驟我都稱為初始化)-----------》init方法的執(zhí)行(invokerInitMethods,下文稱為init)
postprocessor的方法就是穿插在這三個(gè)大的步驟中。
BeanPostProcessor:

postProcessBeforeInitialization調(diào)用時(shí)機(jī)
向上找調(diào)用者:

繼續(xù)向上:

看以看出populateBean(初始化bean)-------------------》beanpostBeforeInitialization---------------------------------->invokeinitMethods(配置的init-method)
postProcessAfterInitialization調(diào)用時(shí)機(jī):

向上:

可以看出在init-method方法之后
看以看出populateBean(初始化bean)-------------------》beanpostBeforeInitialization---------------------------------->invokeinitMethods(配置的init-method)------->postProcessAfterInitialization
public class MBeanPostProcessor implements BeanPostProcessor {
@Override
//populateBean之后 invokeinitMethods之前
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post bean before! :"+beanName);
return bean;
}
@Override
//invokeinitMethods之后
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("post bean after!"+beanName);
return bean;
}
}
另一個(gè)重要的是:
InstantiationAwareBeanPostProcessor

postProcessBeforeInstantiation調(diào)用時(shí)機(jī):

向上找調(diào)用者:

繼續(xù)向上:

可以看出是在實(shí)例化之前:(也就是反射創(chuàng)建對(duì)象之前,如果postProcessBeforeInstantiation創(chuàng)建了一個(gè)非空的對(duì)象,則不會(huì)走實(shí)例化步驟。)
postProcessAfterInstantiation調(diào)用時(shí)機(jī):
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//在這里執(zhí)行
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
省略。。。。。
applyPropertyValues(beanName, mbd, bw, pvs);
}
可以看出是在在初始化之前,具體是屬性填充之前。(初始化之前,實(shí)例化之后) 如果返回fales,則不會(huì)繼續(xù)初始化,即不會(huì)屬性填充。
postProcessPropertyValues調(diào)用時(shí)機(jī):
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
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);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
在postProcessAfterInstantiation之后,applyPropertyValues之前。(屬性填充之前修改屬性值)
總結(jié): 執(zhí)行順序
- 1.postProcessBeforeInstantiation(實(shí)現(xiàn)這個(gè)方法可以做自定義實(shí)例化)
- 2.實(shí)例化
- 3.postProcessAfterInstantiation(是否要初始化)
- 4.postProcessPropertyValues(修改屬性)
- 5.初始化(屬性填充)(populateBean)
- 6.postProcesstBeforeInitialization( 自定義init方法執(zhí)行之前)
- 7.invokeinitMethods(執(zhí)行自定義的init方法)
- 8.postProcessAfterInitialization(自定義init方法執(zhí)行之后)
如果加上aware

- 1.postProcessBeforeInstantiation(實(shí)現(xiàn)這個(gè)方法可以做自定義實(shí)例化)
- 2.實(shí)例化
- 3.postProcessAfterInstantiation(是否要初始化)
- 4.postProcessPropertyValues(修改屬性)
- 5.初始化(屬性填充)(populateBean)
- 6.postProcesstBeforeInitialization( 自定義init方法執(zhí)行之前)
- 7.invokeAwareMethod
- 8.invokeinitMethods(執(zhí)行自定義的init方法)
- 9.postProcessAfterInitialization(自定義init方法執(zhí)行之后)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java開發(fā)中POJO和JSON互轉(zhuǎn)時(shí)如何忽略隱藏字段的問題
這篇文章主要介紹了Java開發(fā)中POJO和JSON互轉(zhuǎn)時(shí)如何忽略隱藏字段的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
SpringBoot3+graalvm:整合并打包為可執(zhí)行文件方式
本文介紹了如何在Spring Boot 3中整合GraalVM,并將其打包為可執(zhí)行文件,適用于Windows和Linux系統(tǒng),通過安裝GraalVM、配置環(huán)境變量、下載Visual Studio組件(僅限Windows)以及使用Maven容器(適用于Linux),可以實(shí)現(xiàn)高效的打包和運(yùn)行2024-12-12
詳解java.lang.NumberFormatException錯(cuò)誤及解決辦法
這篇文章主要介紹了詳解java.lang.NumberFormatException錯(cuò)誤及解決辦法,本文詳解的介紹了錯(cuò)誤的解決方法,感興趣的可以一起來了解一下2020-05-05
Java利用Easyexcel導(dǎo)出excel表格的示例代碼
這篇文章主要為大家詳細(xì)介紹了Java利用Easyexcel導(dǎo)出excel表格的示例代碼,文中的代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2022-07-07

