Spring源码学习笔记5——注册BeanPostProcessor,初始化事件多播器,注册事件监听器
一丶前言
上篇Spring容器回调完所有的BeanFactoryPostPocessor,之后可以做到替换所有占位符,解析所有配置类等工作,这篇还会迎来一个Spring留给我们扩展的一个接口,涉及到Aop的实现
二丶注册BeanPostProcessor后置处理器
1.什么是BeanPostProcessor
一个允许自定义修改新 bean 实例的工厂接口,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的
和上篇的 BeanFactoryPostProcessor 名称很像,但是BeanFactoryPostProcessor是针对整个BeanFactory 进行操作,允许我们修改BeanDefinition,注册我们自己的BeanDefinition等,针对一个Bean使用BeanPostProcessor更好,可以为这个Bean生成一个代理
public interface BeanPostProcessor {
// bean实例化但属性没有填充时回调
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// bean 依赖注入,属性填充后调用
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
2.注册BeanPostProcessor

处理流程也比较简单,获取BeanFactory中的BeanPostProcessor类型的bean,对于实现PriorityOrdered的BeanPostProcessor,排序并优先放入BeanPostProcessor集合中(通常是一个CopyOnWriteList)先放意味着会先执行,对于实现Ordered的BeanPostProcessor,排序再放入,没有实现Ordered or PriorityOrdered的BeanPostProcessor,不会排序,直接放入(注意这说明BeanPostProcessor的顺序不会受到@Order注解的影响,可能是觉得BeanPostProcessor肯定是需要编写一个类实现接口的,那么继承以下Ordered 和PriorityOrdered吧 )最后对于实现了MergedBeanDefinitionPostProcessor的BeanPostProcessor进行放入,最后把ApplicationListenerDetector放在末尾(笔记三说过这个类,主要是在监听器类型的bean被销毁的时候,会从事件多播器中移除)
3.MergedBeanDefinitionPostProcessor

MergedBeanDefinitionPostProcessor 的调用是在创建完 bean 实例之后,在 Bean属性填充 之前,将调用 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法。
3.1 CommonAnnotationBeanPostProcessor
解析类中的@Resource,@PostConstruct,@PreDestroy,并且正确的时机执行


其中这个类还实现了 InstantiationAwareBeanPostProcessor,在Bean设置属性的时候,获取@Resouce注解并且进行依赖注入
3.2 AutowiredAnnotationBeanPostProcessor
解析@Autowrie,和@Value注解,在依赖注入的时候发会作用
还要很多和Bean生命周期相关的接口,贯穿bean的生命周期,这个后续Bean生命周期学习中进行总结
三丶初始化事件多播器

1.AbstractApplicationContext推送事件

注意当前容器执行之后还会调用父容器中的监听器响应
2.SimpleApplicationEventMulticaster
事件多播器的简单实现
2.1 推送事件


四丶注册事件监听器

负责把事件监听器 注册到多播器中,并且在事件多播器初始化执行之前,可能存在一些事件没有处理,这些事件都会放在earlyApplicationEvents集合中,在多播器初始化后,会把earlyApplicationEvents置为null 以后的事件都是直接委托给多播器进行推送
1.对于@EventLister的方法是怎么注册
这种类型的方法被封装成了ApplicationLister,也是在注册事件监听器会注册到多播器中,注册到多播器,存在一个类——EventListenerMethodProcessor负责处理这些方法,在调用所有BeanFactoryPostProcessor的时候会调用到
EventListenerMethodProcessor
1.1类结构图

- SmartInitializingSingleton 具有方法 afterSingletonsInstantiated 在bean初始化后会被容器回调使用
1.2 初始化解析Method 生成ApplicationLister的策略
EventListenerMethodProcessor的 postProcessBeanFactory方法

public interface EventListenerFactory {
//是否可以把当前方法包装成一个 ApplicationListener
boolean supportsMethod(Method method);
// 当前bean的名称 和 标注事件监听注解的方法 生成一个ApplicationListener
ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);
}

具有两个实现,这EventListenerMethodProcessor使用策略模式,调用者两个类,把符合要求的方法封装成ApplicationLister对象,注册到上下文(上下文会把它们注册到多播器)
1.3把标有@EventLister注册的方法封装成ApplicationListener
在afterSingletonsInstantiated方法中实现,在bean初始化后会被容器回调使用,获取容器中所有的bean,调用processBean方法把其中标注@EventListener的方法,or @EventListener符合注册的方法,包装一个ApplicationListener 并且注册到上下文中
1.3.1获取具有@EventLister注解的方法

1.3.2 使用对应的策略生成ApplicationListner
超级经典的 策略+工厂+责任链设计模式,妙呀
2.DefaultEventListenerFactory&ApplicationListenerMethodAdapter

默认的策略,直接new 一个ApplicationListenerMethodAdapter

2.1 ApplicationListenerMethodAdapter构造方法
这里的order 来自@Order注解 如果没有注解那么默认最低优先级,这里的condition
2.2 处理事件

解析参数

反射执行

返回值处理

我们可以返回CompletionStage<事件,异常>会继续推送事件
如果返回的是ListenableFuture(继承了Future)在执行完后进行回调——继续推送事件
3.TransactionalEventListenerFactory&TransactionalApplicationListenerMethodAdapter


TransactionSynchronizationManager 这个类有点复杂后续详细学习
如果事务处于活跃状态


Spring源码学习笔记5——注册BeanPostProcessor,初始化事件多播器,注册事件监听器的更多相关文章
- Spring 源码学习笔记11——Spring事务
Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Spring 源码学习笔记10——Spring AOP
Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...
- Spring源码学习笔记9——构造器注入及其循环依赖
Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...
- spring源码学习笔记之容器的基本实现(一)
前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...
- Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析
bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...
- Spring源码学习笔记之bean标签属性介绍及作用
传统的Spring项目, xml 配置bean在代码中是经常遇到, 那么在配置bean的时候,这些属性的作用是什么呢? 虽然说现在boot项目兴起,基于xml配置的少了很多, 但是如果能够了解这些标签 ...
- Spring源码学习笔记2
1.默认标签的解析 对四种不同标签的解析 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate dele ...
- vue 2.0源码学习笔记—new Vue ( Vue 初始化过程 )
new Vue(Vue 初始化) 一个vue实例化到底经历了什么?已下是博主自己的总结,不正确的地方请指出,谢谢~ 一.简述 从使用角度来看,挂载的顺序如下 1. $slots 2. $scopedS ...
- Spring源码学习笔记1
1.Spring中最核心的两个类 1)DefaultListableBeanFactory XmlBeanFactory继承自DefaultListableBeanFactory,DefaultLis ...
随机推荐
- 如何配置.h头文件include“”相对路径
编译工程时,找的是当前main.c文件下的.h文件,如果当前路径下没有就会报错,当前路径用.\表示,上一级目录用..\表示. 如果你的main.h文件在main.c的上一级目录中Include 文件夹 ...
- c语言代码练习2(2)改进
//利用for循环计算1-10阶乘的和#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main( ) { int num ...
- 【高手训练】【RMQ】奶牛排队
第一题由于过水,就没写awa 大概就是这样了.题意就是求一个最长的区间使得区间的左边是它的最小值,区间右边是他的最大值第一个想法肯定是暴力枚举啦awa但是这个是O(n^3)的,绝对的不可过awa 思考 ...
- Trino容错模式深度测评与思考
本文分享自华为云社区<走向批处理-交互式分析一体化: Trino容错模式深度测评与思考>,作者:HetuEngine九级代言 . 本文系华为云大数据研发团队原创,原创作者:文博,梦月 1 ...
- getc()、getchar()、getch() 和 getche() 的区别
所有这些函数都从输入中读取一个字符并返回一个整数值.返回整数以容纳用于指示失败的特殊值.EOF值通常用于此目的. getc() 它从给定的输入流中读取单个字符,并在成功时返回相应的整数值(通常 ...
- 探究——C# .net 代码混淆/加壳
背景: 保密. 过程: 先查询一下常见的加壳工具: DotFuscator,官方自带,据说免费版混淆程度不高 Virbox Protector,很好很优秀,但是收费 NET Reactor,可能会被识 ...
- [SWPUCTF 2021 新生赛]非常简单的逻辑题
一道简单的代码逆向,根据提供的py代码写出逆向代码,没怎么做过这种题开始没什么思路,原来直接暴力就好 直接写出暴力代码
- 微服务系列-基于Spring Cloud Eureka进行服务的注册与消费
公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享. 在之前的几个教程中,我们学了: 使用 RestTemplate 的 Spring Boot 微服务通信示例 使用 WebC ...
- 2022.7.15 jiazhaopeng 讲课纪要
前言 由于难度仍然过高,难度再次下调,这节课主要在水绿.这节课讲的是并查集,之所以是以绿题为主是因为上了绿之后的题有一大半都要结合别的东西,初中生不会,所以只能讲的简单一点. ORZ%%% jzp学长 ...
- STL set容器
set 使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等. 举个例子,如下有 2 组键值对数据: {<'a', 1>, <'b', 2>, < ...