spring源码分析——BeanPostProcessor接口
BeanPostProcessor是处理bean的后置接口,beanDefinitionMaps中的BeanDefinition实例化完成后,完成populateBean,属性设置,完成
初始化后,这个接口支持对bean做自定义的操作。
一:BeanPostProcessor的使用
定义一个测试用的model对象,name属性默认为hello
public class BeanDemo {
private String name = "hello";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("BeanDemo{");
sb.append("name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}
自定义一个MyBeanPostProcessor类,实现BeanPostProcessor接口
@Service
public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return null;
} public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("beanDemo")){
BeanDemo beanDemo = (BeanDemo)bean;
beanDemo.setName("kitty");
return beanDemo;
}
return bean;
}
}

从运行结果看,spring中维护的beanName为beanDemo的对象,name属性为ketty

二:看看源码怎么实现的
1:实例化并且注册到beanPostProcessors集合中


主要的实例化逻辑在这个接口,这个接口的作用就是把所有实现BeanPostProcessor接口的类实例化,然后注册到 beanPostProcessors这个缓存中

public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { // 获取所有实现接口BeanPostProcessor的beanName
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
/**
* 把实现PriorityOrdered 和 Ordered 和 其他的处理器分开
*/
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
/**
* 1:遍历集合postProcessorNames
* 2:判断类型,如果是PriorityOrdered,则实例化对象放入priorityOrderedPostProcessors集合,
* Ordered 则放入orderedPostProcessorNames集合,其他的放入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)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
} // First, register the BeanPostProcessors that implement PriorityOrdered.
// 首先对priorityOrderedPostProcessors集合中实例对象排序,然后注册,放入beanFactory中缓存下来
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered.
// 然后再实例化实现Ordered接口的对象,完成注册
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(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors.
// 最后实例化什么都没有实现的,完成实例化并注册
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); // Finally, re-register all internal BeanPostProcessors.
// 最后再次注册内部postProcessor
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

定义四类容器,高优先级有序、有序、无序、内部

分类放入四种容器:

注册BeanPostProcessor,将实现BeanPostProcessor接口的对象放入beanPostProcessors缓存中



注册完PriorityOrdered的实现类后,再处理Ordered的实现类

注册什么都没有实现的BeanPostProcessor接口实现类,

最后注册内部的BeanPostProcessor对象

到这里BeanPostProcessor的实例化以及注册工作完成,在beanFactory的beanPostProcessors集合中已经缓存了所有的beanPostProcessor的对象
2:BeanPostProcessor的使用
因为这个接口是bean的后置接口,所以需要bean创建并初始化完成,才可以发挥作用,上一步的缓存只是埋好点,以备使用,因为bean的实例化流程我们
还没有分析,这里直接看一下怎么使用的

我们看一下init方法后的拦截,因为这个时候已经init完成,可以在后置接口中对bean做一下修改的操作

调用到我们自定义的MyBeanPostProcessor实现类:

把这个beanDemo对象属性修改一下,修改完,再返回,将这个对象缓存到spring的一级缓存中。

总结:
BeanPostProcessor接口主要是对bean对象做一些自定义的操作,修改bean对象的信息,aop代理也是通过这种方式实现的,
在refresh的registryBeanPostProcessor方法中实例化BeanPostProcessor对象,并且注册到beanFactory容器的beanPostProcessors的缓存中,
然后在后续的操作中拦截使用。
spring源码分析——BeanPostProcessor接口的更多相关文章
- spring源码分析系列 (2) spring拓展接口BeanPostProcessor
Spring更多分析--spring源码分析系列 主要分析内容: 一.BeanPostProcessor简述与demo示例 二.BeanPostProcessor源码分析:注册时机和触发点 (源码基于 ...
- spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...
- spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor
更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...
- Spring源码分析——BeanFactory体系之抽象类、类分析(二)
上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之 ...
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
代码入口 上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了f ...
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...
- 【spring源码分析】IOC容器初始化(一)
前言:spring主要就是对bean进行管理,因此IOC容器的初始化过程非常重要,搞清楚其原理不管在实际生产或面试过程中都十分的有用.在[spring源码分析]准备工作中已经搭建好spring的环境, ...
随机推荐
- Channels集成到Django消息实时推送
channel架构图 InterFace Server:负责对协议进行解析,将不同的协议分发到不同的Channel Channel Layer:频道层,可以是一个FIFO队列,通常使用Redis Dj ...
- hashMap探析
本篇文章包括: 数据结构 各个参数 为什么数组的长度是2的整数次方 为什么要将装载因子定义为0.75 为什么链表转红黑树的阈值为8 hash碰撞 put方法 resize方法 jdk7中数组扩容产生环 ...
- 15 . PythonWeb框架本质
PythonWeb框架的本质 简单描述就是:浏览器通过你输入的网址给你的socket服务端发送请求,服务端接受到请求给其回复一个对应的html页面,这就是web项目.所有的Web应用本质上就是一个so ...
- K-means聚类分析
一.原理 先确定簇的个数,K 假设每个簇都有一个中心点 centroid 将每个样本点划分到距离它最近的中心点所属的簇中 选择K个点做为初始的中心点 while() { 将所有点分配个K个中心点形成K ...
- DFA最小化
1.将DFA最小化:教材P65 第9题 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 3.自上而下语法分析,回溯产生的原因是什么? 文法中,对于某个非终结符号的规 ...
- SpringCloud Eureka Client和Server侧配置及Eureka高可用配置
一.Eureka注册中心和客户端配置Demo. 1.Server端 a.使用Idea创建Spring项目,如下所示: b.相关配置 application.yaml配置文件如下: # eureka本身 ...
- Java实现 LeetCode 587 安装栅栏(图算法转换成数学问题)
587. 安装栅栏 在一个二维的花园中,有一些用 (x, y) 坐标表示的树.由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树.只有当所有的树都被绳子包围时,花园才能围好栅栏.你需要找到正好 ...
- Java实现 LeetCode 532 数组中的K-diff数对(双指针,滑动窗口)
532. 数组中的K-diff数对 给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对.这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数 ...
- Java实现 LeetCode 399 除法求值
399. 除法求值 给出方程式 A / B = k, 其中 A 和 B 均为代表字符串的变量, k 是一个浮点型数字.根据已知方程式求解问题,并返回计算结果.如果结果不存在,则返回 -1.0. 示例 ...
- Java实现 LeetCode 5355 T 秒后青蛙的位置
5355. T 秒后青蛙的位置 给你一棵由 n 个顶点组成的无向树,顶点编号从 1 到 n.青蛙从 顶点 1 开始起跳.规则如下: 在一秒内,青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点(如果它 ...