前言

BeanPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下

public interface BeanPostProcessor {

    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

当你实现了这个接口的时候,Spring会保证在每一个bean对象初始化方法调用之前调用postProcessBeforeInitialization方法,在初始化方法调用之后调用postProcessAfterInitialization

BeanPostProcessor的注册

看过我之前写的IOC源码分析系列文章的同学应该对这个都比较有印象



Spring在执行到这的时候会把所有实现BeanPostProcessor接口的实现类都注册到BeanFactory中,一起来看一下实现的细节

	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//获取所有BeanPostProcessor的实现类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // 这里把实现PriorityOrdered接口,Ordered 接口的BeanPostProcessors 和其他类型的BeanPostProcessors 区分开
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} //对实现了PriorityOrdered接口的按优先级排序
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
//这里就是注册了,下面会说
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
//注册
registerBeanPostProcessors(beanFactory, orderedPostProcessors); List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//注册
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 最后注册常规的
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

可以看到上方的代码就是把这些BeanPostProcessor分为了几类,然后分别根据规则排序后注册进BeanFactory中,而BeanFactory中其实就只是维护了一个BeanPostProcessor的列表而已

  private final List<BeanPostProcessor> beanPostProcessors = new ArrayList();

private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) { for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
} public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
} if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
} }

执行原理

我们知道Bean的初始化是在定义在容器的刷新过程中,而具体的实现则是由AbstractAutowireCapableBeanFactory.initializeBean()方法完成的。在这个方法中就包含了BeanPostProcessor的调用逻辑

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
} Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessors 的Before 方法
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()) {
// BeanPostProcessors 的After方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

而这里面的执行逻辑我们也可以猜到,无非就是循环遍历所有的BeanPostProcessor,然后一一执行


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;}

其中applyBeanPostProcessorsAfterInitialization的实现内容跟这个是一样的

但是这里面有一个主意的点,那就是如果具体的实现一但返回null,那么就会跳出for循环,后面的就得不到机会执行了

常见用例

查看这个接口的继承体系,可以看到这个接口的实现类是非常多的,各个实现类的功能如果感兴趣大家可以去慢慢挖掘一下

Spring扩展点之BeanPostProcessor的更多相关文章

  1. Spring扩展点之Aware接口族

    引言 Spring中提供了各种Aware接口,方便从上下文中获取当前的运行环境,比较常见的几个子接口有:BeanFactoryAware,BeanNameAware,ApplicationContex ...

  2. Spring扩展点-v5.3.9

    Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...

  3. Spring扩展点之BeanFactoryPostProcessor

    前言 BeanFactoryPostProcessor接口是Spring中一个非常重要的接口,它的接口定义如下 public interface BeanFactoryPostProcessor { ...

  4. Spring扩展点之FactoryBean接口

    前言 首先看一下接口定义 public interface FactoryBean<T> { /** * 返回对象实例 */ @Nullable T getObject() throws ...

  5. spring扩展点之PropertyPlaceholderConfigurer

    原理机制讲解 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html 使用时多个配置讲解 ht ...

  6. Spring中的扩展点

    Spring作为一个常用的IOC框架,在设计上预留了很多的扩展点,很多第三方开源框架,包括Spring自身也是基于这些扩展点实现的,这很好的体现了对修改关闭.对扩展开放的原则.总的来说Spring的扩 ...

  7. Spring系列14:IoC容器的扩展点

    Spring系列14:IoC容器的扩展点 回顾 知识需要成体系地学习,本系列文章前后有关联,建议按照顺序阅读.上一篇我们详细介绍了Spring Bean的生命周期和丰富的扩展点,没有阅读的强烈建议先阅 ...

  8. 三万字盘点Spring/Boot的那些常用扩展点

    大家好,我是三友. Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的.本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展 ...

  9. Spring Boot 中如何使用 Dubbo Activate 扩展点

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司的核心竞争力在于创新 – <启示录> 』 继续上一篇:< Spri ...

随机推荐

  1. ubuntu 16.04下node和pm2安装

    一.安装node,这里安装9.0的版本,安装其它版本直接到https://deb.nodesource.com/setup_9.x找相应版本的更改既可 1.sudo apt-get remove no ...

  2. pytest怎么标记用例?

    pytest还有一个很强大的功能,那就是标记用例这个功能,这个功能可真的是很实用哒 首先,我们要实现标记功能,得分为3步走: 1.注册标记 2.标记用例 3.运行已经标记的用例. 那么第一步我们怎么实 ...

  3. torchline:让Pytorch使用的更加顺滑

    torchline地址:https://github.com/marsggbo/torchline 相信大家平时在使用Pytorch搭建网络时,多少还是会觉得繁琐,因为我们需要搭建数据读取,模型,训练 ...

  4. visual studio之X64调试问题

    这个问题没有解决. 只能X86啦!

  5. Hello,DTOS!(中)

    org 0x7c00   //主引导程序的入口地址为0x7c00(物理地址),类似于用c或c++程序中的main函数. start:  //定义标签,标签的含义就是mov ax,cs这条指令的地址. ...

  6. Github实战测试情况

    测试情况 很久没有熬夜测试程序了,经过测试,没有复现功能的有echo.葫芦娃.火鸡堂.那周余嘉熊掌将得队.为了交项目而干杯.修!咻咻!.云打印和追光的人.据汪老师反应在现场实践课程中大都能实现的,公平 ...

  7. html表格及列表

    表格的属性: border:边框 cellpadding:内边距  单元格边框跟内容之间的间距 cellspacing:外边距  单元格跟单元格之间的距离 align:表格的对其样式 width:宽度 ...

  8. React组件简单介绍

    组件是 React 的核心,因此了解如何利用它们对于创建优秀的设计结构至关重要. 组件之间传递信息方式: 1.(父组件)向(子组件)传递信息 2.(子组件)向(父组件)传递信息 3.没有任何嵌套关系的 ...

  9. [NOI2014]动物园(KMP,字符串)

    半年前看这题还感觉很神仙,做不动(没看题解). 现在过来看发现……这tm就是一个sb题…… 首先题面已经提示我们用 KMP 了.那 KMP 究竟能干啥呢? 看 $num$ 的定义.发现对于前缀 $i$ ...

  10. php-fpm指定配置文件及php相关配置命令

    [root@hostname centos7 sbin]# ./php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm. ...