相关文章

上一篇文章我们聊了下 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 中找到所有实现了 BeanPostProcessorbeanName、然后反手就注册一个叫做 BeanPostProcessorCheckerBeanPostProcessor 。这个类有什么作用呢、下次一定跟大家一起学习一下、下次一定

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 存放的实现了 PriorityOrderedMergedBeanDefinitionPostProcessor 接口的( MergedBeanDefinitionPostProcessor 继承 BeanPostProcessor ),可以认为 internalPostProcessorspriorityOrderedPostProcessors 的子集
  • 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的更多相关文章

  1. Spring8:一些常用的Spring Bean扩展接口

    前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...

  2. spring bean生命周期管理--转

    Life Cycle Management of a Spring Bean 原文地址:http://javabeat.net/life-cycle-management-of-a-spring-be ...

  3. 0003 - 基于xml的Spring Bean 的创建过程

    一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...

  4. Spring Bean状态(转)

    Spring-beans的核心实体是BeanDefinition和BeanFactory.前者映射我们的定义,后者则是依据定义生产bean的工厂.  上图是spring beans的静态结构图,更多是 ...

  5. 🙈羞,Spring Bean 初始化/销毁竟然有这么多姿势

    文章来源:http://1t.click/bfHN 一.前言 日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源.Spring 框架提供相关功能,围绕 Spring Bean ...

  6. Spring(三)--Spring bean的生命周期

    Spring bean的生命周期 ApplicationContext Bean生命周期流程 1.需要的实体类 ackage com.xdf.bean; import org.springframew ...

  7. Spring Bean各阶段生命周期的介绍

    一.xml方式配置bean 二.Aware接口 2.1 BeanNameAware 2.2 BeanFactoryAware 2.3 ApplicationContextAware 2.4 Aware ...

  8. Spring Bean详细讲解

    什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象. Spring 容器会自动完成@bean对象的实例化. 创建应用对象之间的协作关系的行为称为:装配( ...

  9. Spring Bean的生命周期(非常详细)

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

随机推荐

  1. Java实现 LeetCode 752 打开转盘锁(暴力)

    752. 打开转盘锁 你有一个带有四个圆形拨轮的转盘锁.每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' .每个拨轮可以自由旋 ...

  2. Java实现 LeetCode 741 摘樱桃(DFS || 递推 || 传纸条)

    741. 摘樱桃 一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示: 0 表示这个格子是空的,所以你可以穿过它. 1 表示这个格子里装着一个樱桃,你可以摘到樱桃然 ...

  3. Java实现 LeetCode 4 寻找两个有序数组的中位数

    寻找两个有序数组的中位数 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 n ...

  4. Java 是如何实现跨平台的?

    Java 是如何实现跨平台的? 注意:跨平台的是 Java 程序,而不是 JVM.JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM 答:我们编写的 ...

  5. java实现棋盘上的麦子

    ** 棋盘上的麦子** 你一定听说过这个故事.国王对发明国际象棋的大臣很佩服,问他要什么报酬,大臣说:请在第1个棋盘格放1粒麦子,在第2个棋盘格放2粒麦子,在第3个棋盘格放4粒麦子,在第4个棋盘格放8 ...

  6. java实现第七届蓝桥杯煤球数量

    煤球数量 煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形), - 如果一共有100层,共有多少个煤 ...

  7. python—面向对象设计

    一:三大编程范式 1.面向过程编程 2.函数式编程 3.面向对象编程 (类:把一类事物的相同的特征和动作整合到一起就是类,类是一个抽象的概念) (对象:就是基于类而创建的一个具体的事物 [具体存在的] ...

  8. HttpUtil工具类,发送Get/Post请求,支持Http和Https协议

    HttpUtil工具类,发送Get/Post请求,支持Http和Https协议 使用用Httpclient封装的HttpUtil工具类,发送Get/Post请求 1. maven引入httpclien ...

  9. 实验四 Linux系统C语言开发环境学习

    项目 内容 这个作业属于哪个课程 Linux系统与应用 这个作业的要求在哪里 作业要求链接 学号-姓名 17041428-朱槐健 作业学习目标 1.Linux系统下C语言开发环境搭建 2.学习Linu ...

  10. uni-app动态修改顶部导航栏标题

    动态修改顶部导航栏标题有两种方法方式一.使用自定义到导航栏,覆盖原生导航栏 缺点:自定义到导航栏性能远远不如原生导航栏,手机顶部状态栏区域会被页面内容覆盖,这是因为窗体是沉浸式的原因,即全屏可写内容: ...