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接口(BeanNameAwareBeanClassLoaderAwareBeanFactoryAware),以便在后面的处理过程中可能会使用到,所以提前处理

其它的Aware接口会通过BeanPostProcessor去处理。

重点来了

applyBeanPostProcessorsBeforeInitialization 通过调用此方法去遍历Spring容器中的 BeanPostProcessor,并执行其 postProcessBeforeInitialization 方法

invokeInitMethods 通过调用此方法完成以下的一些操作

  • afterPropertiesSet方法的调用
  • 调用自定义的init-method方法

applyBeanPostProcessorsAfterInitialization 通过调用此方法去遍历Spring容器中的 BeanPostProcessor,并执行其 postProcessAfterInitialization 方法

在applyBeanPostProcessorsBeforeInitialization中我可以看到我们常用的一些BeanPostProcessor调用

  • ApplicationContextAwarePostProcessor 处理我们的几个Spring中提供的Aware接口

    EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware
  • 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)的更多相关文章

  1. Spring中BeanPostProcessor

    Spring中BeanPostProcessor 前言: 本文旨在介绍Spring动态配置数据源的方式,即对一个DataSource的配置诸如jdbcUrl,user,password,driverC ...

  2. spring中BeanPostProcessor之一:InstantiationAwareBeanPostProcessor(01)

    在spring中beanPostProcessor绝对是开天辟地的产物,给了程序员很多自主权,beanPostProcessor即常说的bean后置处理器. 一.概览 先来说下Instantiatio ...

  3. spring扩展点整理

    本文转载自spring扩展点整理 背景 Spring的强大和灵活性不用再强调了.而灵活性就是通过一系列的扩展点来实现的,这些扩展点给应用程序提供了参与Spring容器创建的过程,好多定制化的东西都需要 ...

  4. Spring 的 BeanPostProcessor接口实现

    今天学习了一下Spring的BeanPostProcessor接口,该接口作用是:如果我们需要在Spring容器完成Bean的实例化,配置和其他的初始化后添加一些自己的逻辑处理,我们就可以定义一个或者 ...

  5. spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情

    <spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...

  6. spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入

    <spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...

  7. spring中BeanPostProcessor之三:InitDestroyAnnotationBeanPostProcessor(01)

    在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>一文中,分析到在调用CommonAnnotationB ...

  8. spring中BeanPostProcessor之四:AutowiredAnnotationBeanPostProcessor(01)

    在<spring中BeanPostProcessor之二:CommonAnnotationBeanPostProcessor(01)>中分析了CommonAnnotationBeanPos ...

  9. spring扩展点之一:BeanFactoryPostProcessor和BeanPostProcessor

    一.BeanFactoryPostProcessor和BeanPostProcessor的区别 BeanFactoryPostProcessor和BeanPostProcessor都是spring初始 ...

  10. Spring的BeanPostProcessor和BeanFactoryPostProcessor区别

    Spring提供了两种后处理bean的扩展接口,分别为BeanPostProcessor和BeanFactoryPostProcessor,这两者在使用上是有所区别的. BeanPostProcess ...

随机推荐

  1. Serverless Kubernetes:理想,现实与未来

    简介: 当前 Serverless 容器的行业趋势如何?有哪些应用价值?如果 Kubernetes 天生长在云上,它的架构应该如何设计?Serverless 容器需要哪些基础设施?阿里云容器服务产品负 ...

  2. NBF事件中心架构设计与实现

    ​简介:NBF是阿里巴巴供应链中台的基础技术团队打造的一个技术PaaS平台,她提供了微服务FaaS框架,低代码平台和中台基础设施等一系列的PaaS产品,旨在帮助业务伙伴快速复用和扩展中台能力,提升研发 ...

  3. 基于 Observable 构建前端防腐策略

    ​简介:To B 业务的生命周期与迭代通常会持续多年,随着产品的迭代与演进,以接口调用为核心的前后端关系会变得非常复杂.在多年迭代后,接口的任何一处修改都可能给产品带来难以预计的问题.在这种情况下,构 ...

  4. Alibaba FFI -- 跨语言编程的探索

    ​简介: 跨语言编程时现代程序语言中非常重要的一个方向,也被广泛应用于复杂的设计与实现中. 跨语言编程是现代程序语言中非常重要的一个方向,也被广泛应用于复杂系统的设计与实现中.本文是 GIAC 202 ...

  5. 数据改变后更新UI(SetProperty/RaiseCanExecuteChanged)

    View代码 1 <StackPanel> 2 <TextBlock Text="方法一"></TextBlock> 3 <TextBox ...

  6. c#胖东来小程序自动购物程序(接单,windows桌面程序、linux程序、网络应用等等)

    一.程序效果 自动打开胖东来小程序,自动购物 二.实现 先截屏,然后利用opencv库识别下一步按键所在位置,然后使用mouse_event控制鼠标,模拟人的动作 第一步,截取屏幕 static Bi ...

  7. ruby rails 批量插入数据,bulk_insert-----Gem包使用

    Gemfile文件里添加 gem 'bulk_insert' #批量插入 命令行执行安装依赖 bundle install 数据源 ["1.180.3.187", 161, 260 ...

  8. 02.go-admin IDE配置配置命令启动方式讲解笔记

    目录 go-admin版本 视频地址 一.代码地址 二.在线文档 三.首次配置需要初始化数据库资源信息(已初始化过数据库的,跳过此步) 配置数据库迁移 五.配置启动项目,用goland IDE进行启动 ...

  9. vue3.0 用vue ui 新建项目

    安装步骤: 1.打开安装界面 打开cmd vue ui 2.选择要安装的位置 3.设置详情 4.设置预设 5.设置功能 选择Babel / Router / Linter/Formatter / 使用 ...

  10. 在jeecg-boot中使用代码生成器&mybatis-plus

    一.代码生成器代码生成器-->jeecgOneGUI配置文件:resource/jeecg/jeecg_config.properties,修改目标生成的路径和包名数据库连接:resource/ ...