Spring扩展——BeanPostProcessor(BPP)
BeanPostProcess简介
在Spring中 BeanPostProcessor 是一个非常重要的接口,它用于在每个bean对象初始化前后修改Bean的属性信息,比如我们最常用的@Autowired注解,在内部处理的时候,是通过一个AutowiredAnnotationBeanPostProcessor类来对bean的属性进行自动注入的,而AutowiredAnnotationBeanPostProcessor也是 BeanPostProcessor的一个实现类。它在createBean的时候会被调用。
1. Spring createBean基本流程图
在Spring中创建Bean对象,我们可以把它看作是两个过程
- 实例化(Spring中通过反射工具进行实例化对象,并将属性设为默认值)
- 初始化(Spring中在初始化前化给属性进行注入操作)

Bean初始化过程

2. BeanPostProcess接口定义
public interface BeanPostProcessor {
/**
* 初始化方法调用前要进行的处理逻辑
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 在初始化方法指定后要进行的处理逻辑
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
它提供了两个方法,一个前置和后置的处理方法,在bean对象实例化前后分别被调用,并会传入一个将要被处理的bean对象,从上面图中我们可以看出,BeanPostProcessor的before 和 after是在init-method前后调用的,我们一起来看一下,createBean的时候这一部分的源码,在createBean的时候,会调用 doCreateBean,所以真正核心的创建流程在doCreateBean方法中
3. doCreateBean (singleton bean)
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在以上创建过程中,我们可以看到几个重要的方法
1. createBeanInstance 实例化Bean对象
2. populateBean 为Bean对象填充属性
3. initializeBean 初始化bean对象
4. 初始化Bean对象
在initializeBean 方法中
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
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);
}
return wrappedBean;
}
首先会调用invokeAwareMethods方法,处理几个特殊的aware接口(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware),以便在后面的处理过程中可能会使用到,所以提前处理
其它的Aware接口会通过BeanPostProcessor去处理。
重点来了
applyBeanPostProcessorsBeforeInitialization 通过调用此方法去遍历Spring容器中的 BeanPostProcessor,并执行其 postProcessBeforeInitialization 方法
invokeInitMethods 通过调用此方法完成以下的一些操作
- afterPropertiesSet方法的调用
- 调用自定义的init-method方法
applyBeanPostProcessorsAfterInitialization 通过调用此方法去遍历Spring容器中的 BeanPostProcessor,并执行其 postProcessAfterInitialization 方法
在applyBeanPostProcessorsBeforeInitialization中我可以看到我们常用的一些BeanPostProcessor调用
- ApplicationContextAwarePostProcessor 处理我们的几个Spring中提供的Aware接口
EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware - ImportAwareBeanPostProcessor 处理被import注解了的bean对象,并进行递归import bean对象
详细的流程图如下

自定义BeanPostProcessor
需要:自定义一个BeanPostProcessor用于打印输出 每个bean 初始化成功的消息
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
/**
* BeanPostProcessor 接口里有默认方法,默认直接将bean返回
*
* @param bean the new bean instance
* @param beanName the name of the bean
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 在后置处理器中,可以对bean对象进行修改操作
* 1. 可以返回其代理对象
* <p>
* 我们这里只输出一下bean创建成功的消息
*
* @param bean the new bean instance
* @param beanName the name of the bean
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + " init successful");
return bean;
}
另外一篇里面也有关于BeanPostProcessor的扩展——https://www.cnblogs.com/yanchuanbin/p/14582813.html
Spring扩展——BeanPostProcessor(BPP)的更多相关文章
- Spring中BeanPostProcessor
Spring中BeanPostProcessor 前言: 本文旨在介绍Spring动态配置数据源的方式,即对一个DataSource的配置诸如jdbcUrl,user,password,driverC ...
- spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(01)
在spring中beanPostProcessor绝对是开天辟地的产物,给了程序员很多自主权,beanPostProcessor即常说的bean后置处理器. 一.概览 先来说下Instantiatio ...
- spring扩展点整理
本文转载自spring扩展点整理 背景 Spring的强大和灵活性不用再强调了.而灵活性就是通过一系列的扩展点来实现的,这些扩展点给应用程序提供了参与Spring容器创建的过程,好多定制化的东西都需要 ...
- Spring 的 BeanPostProcessor接口实现
今天学习了一下Spring的BeanPostProcessor接口,该接口作用是:如果我们需要在Spring容器完成Bean的实例化,配置和其他的初始化后添加一些自己的逻辑处理,我们就可以定义一个或者 ...
- spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入
<spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...
- spring中BeanPostProcessor之三:InitDestroyAnnotationBeanPostProcessor(01)
在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>一文中,分析到在调用CommonAnnotationB ...
- spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)
在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>中分析了CommonAnnotationBeanPos ...
- spring扩展点之一:BeanFactoryPostProcessor和BeanPostProcessor
一.BeanFactoryPostProcessor和BeanPostProcessor的区别 BeanFactoryPostProcessor和BeanPostProcessor都是spring初始 ...
- Spring的BeanPostProcessor和BeanFactoryPostProcessor区别
Spring提供了两种后处理bean的扩展接口,分别为BeanPostProcessor和BeanFactoryPostProcessor,这两者在使用上是有所区别的. BeanPostProcess ...
随机推荐
- Redis消息队列发展历程
简介:Redis是目前最受欢迎的kv类数据库,当然它的功能越来越多,早已不限定在kv场景,消息队列就是Redis中一个重要的功能.Redis从2010年发布1.0版本就具备一个消息队列的雏形,随着1 ...
- Dapr 在阿里云原生的实践
简介: Faas 场景下,比较吸引用户的是成本和研发效率,成本主要通过按需分配和极致的弹性效率来达成.而应用开发者期望通过 FaaS 提供多语言的编程环境,提升研发效率,包括启动时间.发布时间.开发的 ...
- [Go] flag package 指南: 命令行参数标记的解析
flag 是 Golang 的官方包. 支持用法有三种,不同之处是二三两种用法是 Var() 函数可以绑定 flag 到一个变量上. 直接调用指定类型的函数有多种,如 flag.String(), B ...
- [FAQ] Cordova 模拟器中不能访问域名, 未联网 ?
首先保证电脑已联网,然后打开模拟器的浏览器输入常用网址,看看是否能够联网. 如果访问失败,在本机中在 cmd 中 ping www.baidu.com 获得百度的ip地址,然后在浏览器中输入 http ...
- Oracle和达梦:相似度函数:UTL_MATCH
UTL_MATCH介绍: Oracle的UTL_MATCH包是一个提供字符串匹配和相似度计算功能的工具包.它包含了一系列函数,用于执行字符串比较.相似度计算和模式匹配等操作. UTL_MATCH包中的 ...
- HEOI2024省选游记
day 0 上午 没让不跑操的同学帮忙带着包 所以就直接背着跑的操,相当难受 吃完早饭就拿手机来机房了 不得不说看得出来 huge 这届确实打算换一种教学思路 以来就先强调了一堆意料之外的东西 包括但 ...
- ansible系列(33)--ansible实战之部署WEB集群架构(3)
目录 1. 应用环境部署 1.1 nginx编译部署 1.2 PHP编译部署 1.3 mariadb二级制部署 1.4 redis部署 1.5 NFS部署 1.6 keepalived+LVS部署 1 ...
- fastposter发布1.4.5 跨语言的海报生成器
fastposter发布1.4.5 跨语言的海报生成器 v1.4.5 增加了右键菜单,修复了跨域bug 一分钟完成海报开发任务 future: 增加了右键菜单 删除 图层上移 图层下移 优化项目代码文 ...
- 2022年官网下安装ZooKeeper最全版与官网查阅方法
目录 一.环境整合 构建工具(参考工具部署方式) 二.官网下载 三.解压安装 四.配置环境 五.启动运行 六.配置为服务 七.查看设置服务 其他版本安装 构建工具(参考工具部署方式) 一.环境整合 构 ...
- 【PB案例学习笔记】-02 目录浏览器
写在前面 这是PB案例学习笔记系列文章的第二篇,该系列文章适合具有一定PB基础的读者, 通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求. 文章中设计到的源码 ...