spring bean post processor
相关文章
- Spring 整体架构
- 编译Spring5.2.0源码
- Spring-资源加载
- Spring 容器的初始化
- Spring-AliasRegistry
- Spring 获取单例流程(一)
- Spring 获取单例流程(二)
- Spring 获取单例流程(三)
- Spring 循环依赖
- Spring FactoryBean 缓存
- Spring Aware 接口
- Spring beanPostProcessor
上一篇文章我们聊了下 Aware
接口、今天我们再来聊一下 BeanPostProcessor
吧
为了各位客官老爷们看代码方便、不贴代码了、直接截图
其实再 AbstractBeanFactory
中有一个 List
专门存放着所有的 BeanPostProcessor
private final List<BeanPostProcessor> beanPostProcessors;
我们先来一睹 BeanPostProcessor
的真容吧
就那么两个方法
我们写个小例子玩玩呗
运行 demo
, 居然没有打印出来
看来我们需要手动注册一波
defaultListableBeanFactory.addBeanPostProcessor(new Student());
我擦、这波操作有点骚啊、还真别这么写正常编码的时候。再次运行
Student:postProcessBeforeInitialization:student
Student:postProcessAfterInitialization:student
BeanFactory 就这么弱鸡吗 ? 记得 ApplicationContext
是不用我们去注册的
我们使用一下 ApplicationContext
吧那就
运行一波、但是我的填为啥还是没打印呢、我们看看发生了啥、
当创建好 bean
然后回调 BeanPostProcessor
的时候、我们发现、在 beanPostProcessors
中并没有 Student
这个对象、也就是没有加入注册进去
但是我们在 ApplicationContext
初始化之后查看、发现它又在了、这、究竟是怎么回事呢 ( 我怎么这么多屁话 )
我先把调用链给出来吧
ClassPathXmlApplicationContext构造函数-->refresh()-->registerBeanPostProcessors()
registerBeanPostProcessors
看其名就知道它是干啥的了、
registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
代码有点长、我们一点点分析
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
这个代码就是先从已经注册的 beanDefinition
中找到所有实现了 BeanPostProcessor
的 beanName
、然后反手就注册一个叫做 BeanPostProcessorChecker
的 BeanPostProcessor
。这个类有什么作用呢、下次一定跟大家一起学习一下、下次一定
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
然后就定义了四个局部变量存放 beanName
或者 BeanPostProcessor
对象
priorityOrderedPostProcessors
这个是存放即实现了BeanPostProcessor
又实现了PriorityOrdered
接口的internalPostProcessors
存放的实现了PriorityOrdered
和MergedBeanDefinitionPostProcessor
接口的(MergedBeanDefinitionPostProcessor
继承BeanPostProcessor
),可以认为internalPostProcessors
是priorityOrderedPostProcessors
的子集orderedPostProcessorNames
存放实现了Ordered
接口的nonOrderedPostProcessorNames
捡漏上面都不是的
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)) {
// 为啥不在这里调用 getBean 方法、而是在下面的 for 循环中再调用、
orderedPostProcessorNames.add(ppName);
}
else {
// 为啥不在这里调用 getBean 方法、而是在下面的 for 循环中再调用、
nonOrderedPostProcessorNames.add(ppName);
}
}
上面的代码就是遍历获取到的实现了 BeanPostProcessor
接口的 beanName
、如果它也实现了 PriorityOrdered
接口的、那就调用 getBean 方法获取其 bean、如果只是实现了 Ordered 接口或者都没实现的话、那么就直接加入到对应的 List 中。这里留个问题,为啥保存实现 PriorityOrdered 接口的就要保存其 bean、实现 Ordered 或者都没实现的为啥只是保存其 beanName 、在上面的 else if 和 else 里面 getBean 一下不就得了 ?
// 先进行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 注册
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
这里就是对实现了 PriorityOrdered 接口的 先进行排序、优先级高的先注册
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
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(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
后面又重新注册 internalPostProcessors 里面的 BeanPostProcessor ,这个是什么操作呢,我们看看具体的注册方法
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
// 先移除
this.beanPostProcessors.remove(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// 再增加
this.beanPostProcessors.add(beanPostProcessor);
这么操作一波之后、原来注册的 BeanPostProcessor 的位置就会被移动到 List 的尾部了
我们再回到我们上面的问题,我们的 Student 类明明实现了 BeanPostProcessor 接口,但是却没有被回调到
我们看看对应的代码
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
ClassPathXmlApplicationContext构造函数-->refresh()-->registerBeanPostProcessors()
当我们在 refresh 的时候、执行到 registerBeanPostProcessors , 我们发现整个 Spring 管理的 BeanDefinition 集合中、只有 Student 是实现了 BeanPostProcessor 接口的、然后我们通过 getBean 方法去获取这个 bean , 注意这个时候 AbstractBeanFactory 中的 beanPostProcessors 除了 Spring 自己加入的一些 BeanPostProcessor 之外,Student 的对象不存在于此( Student 的对象还没被 Spring 创建出来) , 然后就走 getBean 的流程,走到 doCreateBean、走到 initializeBean 然后回调 BeanPostProcessor ,但是这个时候 Student 对象还是不在 beanPostProcessors 集合中、所以就不会打印了。其实可以得出一个结论,实现了 BeanPostProcessor 的 bean 当自身被 Spring 创建的时候、它是不会被回调到的
而上面还留了一个问题
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
为啥 orderedPostProcessorNames 和 nonOrderedPostProcessorNames 的集合存放的是一个 String , 而不是直接是 BeanPostProcessor ?主要是为了在创建实现 Ordered 接口的类的时候、即实现了 PriorityOrdered 接口又实现了 BeanPostProcessor 接口的对象得到回调,同理当创建非 PriorityOrdered/Ordered 接口的 bean 时,实现了 PriorityOrdered/Ordered 的 BeanPostProcessor 也能得到回调。这也是一种优先级的关系
spring bean post processor的更多相关文章
- Spring8:一些常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
- spring bean生命周期管理--转
Life Cycle Management of a Spring Bean 原文地址:http://javabeat.net/life-cycle-management-of-a-spring-be ...
- 0003 - 基于xml的Spring Bean 的创建过程
一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...
- Spring Bean状态(转)
Spring-beans的核心实体是BeanDefinition和BeanFactory.前者映射我们的定义,后者则是依据定义生产bean的工厂. 上图是spring beans的静态结构图,更多是 ...
- 🙈羞,Spring Bean 初始化/销毁竟然有这么多姿势
文章来源:http://1t.click/bfHN 一.前言 日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源.Spring 框架提供相关功能,围绕 Spring Bean ...
- Spring(三)--Spring bean的生命周期
Spring bean的生命周期 ApplicationContext Bean生命周期流程 1.需要的实体类 ackage com.xdf.bean; import org.springframew ...
- Spring Bean各阶段生命周期的介绍
一.xml方式配置bean 二.Aware接口 2.1 BeanNameAware 2.2 BeanFactoryAware 2.3 ApplicationContextAware 2.4 Aware ...
- Spring Bean详细讲解
什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象. Spring 容器会自动完成@bean对象的实例化. 创建应用对象之间的协作关系的行为称为:装配( ...
- Spring Bean的生命周期(非常详细)
Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...
随机推荐
- Java实现 蓝桥杯VIP 基础练习 报时助手
题目描述 给定当前的时间,请用英文的读法将它读出来. 时间用时h和分m表示,在英文的读法中,读一个时间的方法是: 如果m为0,则将时读出来,然后加上"o'clock",如3:00读 ...
- Java实现 蓝桥杯VIP 算法提高 前10名
算法提高 前10名 时间限制:1.0s 内存限制:256.0MB 问题描述 数据很多,但我们经常只取前几名,比如奥运只取前3名.现在我们有n个数据,请按从大到小的顺序,输出前10个名数据. 输入格式 ...
- Swift 语法总结
1,用 var 定义变量 ,与js类似. let 用于定义常量,定义完后不能修改. var 用于定义变量,可以修改. swift可以自动识别属性类别. 2,使用 import 语句来引入任何的 Obj ...
- 为什么阿里巴巴Java开发手册中强制要求接口返回值不允许使用枚举?
在阅读<阿里巴巴Java开发手册>时,发现有一条关于二方库依赖中接口返回值不允许使用枚举类型的规约,具体内容如下: 在谈论为什么之前先来科普下什么是二方库,二方库也称作二方包,一般指公司内 ...
- SSM框架整合以及书籍管理CRUD系统
1.基本环境搭建 1.新建一Maven项目!ssmbuild , 添加web的支持 2.导入相关的pom依赖! <?xml version="1.0" encoding=&q ...
- Kubernetes-subpath的使用
一.什么是subpath 为了支持单一个pod多次使用同一个volume而设计,subpath翻译过来是子路径的意思,如果是数据卷挂载在容器,指的是存储卷目录的子路径,如果是配置项configMap/ ...
- C#数据结构与算法系列(四):链表——单链表(Single-LinkedList)
1.介绍: 链表是有序的列表,但是它在内存的存储如下: 链表是以节点的方式来存储,链式存储 每一个节点包含data域,next域:指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表 ...
- (十)HttpClient以multipart/form-data上传文件
原文链接:https://blog.csdn.net/wsdtq123/article/details/78888734 POST上传文件 最早的HTTP POST是不支持文件上传的,给编程开发带来很 ...
- 【Spring注解驱动开发】在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean
写在前面 在前面的文章中,我们学习了如何使用@Import注解向Spring容器中导入bean,可以使用@Import注解快速向容器中导入bean,小伙伴们可以参见<[Spring注解驱动开发] ...
- WeChair项目Beta冲刺(1/10)
团队项目进行情况 1.昨日进展 Beta冲刺第一天 前期进展: 对代码进行优化,完成上阶段冲刺未完成的实名认证上传图片的功能,解决解密存在部分失败的bug问题 2.今日安排 前端:设计扫码占座功 ...