目录

一、概述

二、分析@EventListener

2.4 EventListenerMethodProcessor

2.5 DefaultEventListenerFactory

​2.6 ApplicationListenerMethodAdapter

三、分析@TransactionalEventListener

3.3 TransactionalEventListenerFactory

3.4 ApplicationListenerMethodTransactionalAdapter


一、概述

1.1 @EventListener是用来标识在方法上,使得该方法可以监听事件,在事件发布时调用方法处理事件(作用与实现ApplicationListener接口的事件监听器一样,参考分析Spring-ApplicationListener监听器_Just-Today的博客-CSDN博客)。

@EventListener注解有2个属性设置了别名, 分别是value、classes,这2个属性是可用来设置监听器监听事件的类型。

要求:

1、若value()和classes()没有设置值,则标识@EventListener的方法必须有且只能有一个参数。

2、若value()或classes()设置了值,

2.1、单个Class值,则标识@EventListener的方法可以不用设置参数。若想要设置一个参数,则参数的类型一定要是Class或Class的父类或接口。

2.2、多个Class值,官方要求@EventListener的方法一定不要设置参数。若是想要设置一个参数,则参数的类型一定要是所有Class的共同父类或接口。因为在监听事件时,通过反射监听方法处理事件,事件转换成方法参数时,若类型不一致,可能会发生类型转换异常。

1.2 @TransactionalEventListener的注解上标识@EventListener注解,相当于继承了@EventListener注解的功能,并添加了新的特性。

二、分析@EventListener

2.1 创建AnnotationConfigApplicationContext容器对象时,在构造器中创建了一个AnnotatedBeanDefinitionReader类型的reader。

2.2 在AnnotatedBeanDefinitionReader构造器中调用了AnnotationConfigUtils.registerAnnotationConfigProcessors方法。

2.3 registerAnnotationConfigProcessors方法主要是向容器注册创建了一些组件对象。例如扫描解析配置类的ConfigurationClassPostProcessor;解析@Autowired、@Value、@Inject注解的AutowiredAnnotationBeanPostProcessor;解析@Resource注解、@PostConstruct、@PreDestroy的CommonAnnotationBeanPostProcessor等。

其中包含类型为EventListenerMethodProcessor的组件和类型为DefaultEventListenerFactory的组件也注册到容器中。

2.4 EventListenerMethodProcessor

EventListenerMethodProcessor是用来解析@EventListener注解,该类实现了SmartInitializingSingleton、BeanFactoryPostProcessor接口。

2.4.1 在postProcessBeanFactory方法中,从容器中找到类型为EventListenerFactory的组件对象集合,并利用AnnotationAwareOrderComparator的sort方法进行排序,然后赋值给eventListenerFactories。

而DefaultEventListenerFactory实现了EventListenerFactory接口,在这里也会被加入到eventListenerFactories集合中。

2.4.2 容器利用preInstantiateSingletons方法创建初始化非延迟加载的单实例组件后,遍历beanNames(容器组件名称集合),调用getSingleton方法找到实现SmartInitializingSingleton接口的单实例对象,调用对象的afterSingletonsInstantiated方法。

在此时,EventListenerMethodProcessor的afterSingletonsInstantiated方法被调用。

2.4.3 EventListenerMethodProcessor的afterSingletonsInstantiated方法中调用processBean方法。

2.4.4 在processBean方法中,先根据@EventListener得到key为method,value为EventListener的annotatedMethods,annotatedMethods存储了标识@EventListener的方法和注解的相关信息。

接下来,遍历annotatedMethods的key,遍历之前存于EventListenerMethodProcessor.eventListenerFactories的EventListenerFactory对象,先通过factory的supportsMethod判断factory是否支持method。

若支持,则通过factory的createApplicationListener方法创建监听器对象。

而DefaultEventListenerFactory的createApplicationListener方法会为标识@EventListener的方法创建类型为ApplicationListenerEventMethodAdapter的监听器对象,然后将监听器对象加到容器的事件多播器中。

2.5 DefaultEventListenerFactory

DefaultEventListenerFactory实现了EventListenerFactory接口,实现的createApplicationListener方法是为标识@EventListener的方法创建类型为ApplicationListenerMethodAdapter的事件监听器对象,method是标识@EventListener的方法。

2.6 ApplicationListenerMethodAdapter

2.6.1 在ApplicationListenerMethodAdapter构造函数中,通过调用resolveDeclaredEventTypes方法来得到监听器监听事件的类型集合。

进入resolveDeclaredEventTypes方法,标识@EventListener注解的方法若有参数,则只能有一个。

若是classes()属性有值,通过遍历classes属性得到监听器监听事件的类型集合。

若是classes()属性没有值,则标识@EventListener注解的监听方法必须有且只能有一个参数,参数的类型就是监听事件的类型。

2.6.2 ApplicationListenerMethodAdapter实现了GenericApplicationListener接口。

在多播器寻找可以监听事件的监听器时,遍历监听器集合,调用supportsEvent方法。

supportsEvent方法中,将listener监听器转换成GenericApplicationListener,然后调用GenericApplicationListener的supportsEventType方法。

ApplicationListenerMethodAdapter实现了GenericApplicationListener接口,实现的supportsEventType方法中,遍历declaredEventTypes(监听器监听事件的类型集合),

先通过isAssignableFrom方法判断eventType(发布事件的类型)是否是declaredEventType或者它的实现类(继承或实现declaredEventType)。

若是,则表示该监听器可以监听此发布事件,返回true。

若不是,则接着判断eventType是否是PayloadApplicationEvent或者它的实现类。

若是,则得到PayloadApplicationEvent的T泛型类型(也就是payload的实际类型),然后通过isAssignableFrom方法判断payloadType是否是declaredEventType或它的实现类。若是,则返回true。

最后若是集合遍历结束,还没找到可以监听发布事件的类型,则继续调用eventType.hasUnresolvableGenerics()方法继续判断。

2.6.3 后续容器发布事件时,调用ApplicationListenerMethodAdapter对象的onApplicationEvent方法,onApplicationEvent方法了调用processEvent方法。

2.6.4 在processEvent方法中,先通过resolveArguments方法得到反射监听器方法所需要的参数args。如果args为null,则shouldHandle方法会返回false,不反射监听器方法处理事件。

resolveArguments方法先根据getResolvableType方法得到监听器可以监听发布事件的事件类型,

如果返回null,则直接返回。

若不为null,继续往下进行,若监听器方法没有参数,则直接返回空数组。

如果监听器方法含有参数,继续往下,在判断中,如果declaredEventClass不是ApplicationListener的子类(监听事件的类型是普通的Object类型),且发布事件event的类型是PayloadApplicationEvent或它的子类,则判断PayloadApplicationEvent的payload属性和declaredEventClass的关系。若是payload是declaredEventClass的实现类,则返回存储payload的对象数组。

最后返回存储event的对象数组。

getResolvableType方法,先判断发布事件的类型是否是PayloadApplicationEvent或它的子类,若是,则获取payloadType(若是发布事件的类型是普通的Object类型,则容器会为Object创建PayloadApplicationEvent对象,payload属性就是普通的Object类型)。

然后遍历监听器监听事件的类型集合,先判断监听事件的类型如果不是ApplicationEvent的子类且payloadType有值、payloadType是declaredEventType(监听事件的类型)或它的实现类,则返回declaredEventType。

若event(发布事件)是eventClass(监听事件的类型)的实现类,则返回declaredEventType。

若是没找到对应的declaredEventType,则最后返回null。

2.6.3 调用doInvoke方法通过反射运行method,也就是标识@EventListener注解的方法。

2.6.4 若doInvoke方法有返回值,也就是标识@EventListener的方法有返回值时,调用handleResult方法继续发布事件。

注意:若方法有返回值,需处理好,否则容易造成一直循环发布同一事件,导致发生异常。

三、分析@TransactionalEventListener

3.1 @TransactionalEventListener注解类上标识了@EventListener注解,说明@TransactionalEventListener拥有@EventListener注解的功能,在EventListenerMethodProcessor的afterSingletonsInstantiated方法中会被扫描出来。

3.2 通过@EnableTransactionManagement注解开启注解事务时,会向容器注册类型为ProxyTransactionManagementConfiguration的组件对象,而ProxyTransactionManagementConfiguration继承了AbstractTransactionManagementConfiguration。

AbstractTransactionManagementConfiguration通过@Bean注解向容器注册了类型为TransactionalEventListenerFactory的组件。

3.3 TransactionalEventListenerFactory

3.3.1 TransactionalEventListenerFactory实现了EventListenerFactory接口,实现的createApplicationListener方法会为标识@TransactionalEventListener的方法创建类型为ApplicationListenerMethodTransactionalAdapter的对象。

3.3.2 在EventListenerMethodProcessor的postProcessBeanFactory方法中,TransactionalEventListenerFactory对象也会被getBeanOfType方法扫描出来,然后通过AnnotationAwareOrderComparator排序器的sort方法排序,之前容器默认添加的DefaultEventListenerFactory对象会排到TransactionalEventListenerFactory后面,并加入到eventListenerFactories集合中。

3.3.3 在EventListenerMethodProcessor的processBean方法中,遍历eventListenerFactories时,会先遍历到类型为TransactionalEventListenerFactory的对象。

3.3.4 TransactionalEventListenerFactory通过supportsMethod方法判断是否支持method(标识@EventListener、@TransactionalEventListener的方法),

supportsMethod方法支持标识@TransactionalEventListener注解的方法。

3.3.5 若是TransactionalEventListenerFactory支持method,则通过调用TransactionalEventListenerFactory的createApplicationListener方法,创建类型为ApplicationListenerMethodTransactionalAdapter(继承ApplicationListenerMethodAdapter)的监听器对象。(若是没有开启注解事务,则DefaultEventListenerFactory会为标识@TransactionalEventListener的方法创建类型为ApplicationListenerMethodAdapter的对象)

3.4 ApplicationListenerMethodTransactionalAdapter

3.4.1 容器发布事件时,调用ApplicationListenerMethodTransactionalAdapter监听器的onApplicationEvent方法。

3.4.2 先通过TransactionSynchronizationManager.isSynchronizationActive()判断当前线程是否有正在运行的事务。若是有,则通过createTransactionSynchronization方法创建TransactionSynchronizationEventAdapter对象,然后将synchronization注册到当前线程的事务中。

3.4.2.1 容器会对标识@Transactional的方法生成代理对象,运行标识@Transactional注解的方法时,通过代理对象生成拦截器链,调用TransactionInterceptor拦截器的invoke方法开启事务,运行方法。

3.4.2.2 提交事务时,最终会调用事务管理器AbstractPlatformTransactionManager的processCommit方法(详细调用可到源码查看),

在processCommit方法中,会先调用prepareForCommit(提交事务之前做一些准备工作)、triggerBeforeCommit(触发事务TransactionSynchronization的beforeCommit方法)、triggerBeforeCompletion(触发事务TransactionSynchronization的beforeCompletion方法)。

3.4.2.3 进入triggerBeforeCommit方法,调用TransactionSynchronizationUtils.triggerBeforeCommit方法。

3.4.2.4 在TransactionSynchronizationUtils.triggerBeforeCommit方法中,会遍历之前存于当前线程的事务同步TransactionSynchronization集合,调用TransactionSynchronization的beforeCommit方法,

而在之前3.4.2节中,已经将TransactionSynchronizationEventAdapter加入到当前线程的事务同步集合中,所以此时会调用TransactionSynchronizationEventAdapter的beforeCommit方法。

3.4.2.5 TransactionSynchronizationEventAdapter的beforeCommit方法,会先判断@TransactionalEventListener注解的phase值。若是phase等于BEFORE_COMMIT,则调用processEvent方法开始处理事件(参考2.6.2节)。

3.4.2.6 若成功提交事务,则会调用triggerAfterCommit方法触发TransactionSynchronization的AfterCommit方法。

而在afterCommit方法中会调用TransactionSynchronization的afterCommit方法,而之前存储的TransactionSynchronizationEventAdapter对象,没重写该方法,默认为空方法。

3.4.2.7 最终不管事务是提交或者回滚,都会调用triggerAfterCompletion方法,传入TransactionSynchronization的状态值(0表示commit提交事务 1表示rollback回滚事务 2表示unknown,可能发生系统error)。

通过调用invokeAfterCompletion方法遍历当前线程的TransactionSynchronization集合,调用TransactionSynchronization的afterCompletion方法。

TransactionSynchronizationEventAdapter的afterCompletion方法被调用。

3.4.2.8 判断phase和status发布事件,例如phase等于TransactionPhase.AFTER_COMMIT,且事务正常提交,status等于STATUS_COMMITTED(0),则通过processEvent方法处理事件。

3.4.2.9 回滚事务时,最终会调用事务管理器AbstractPlatformTransactionManager的processRollback方法(调用步骤与3.9.2节调用processCommit方法差不多,详细可到源码查看)。

3.4.3 若是当前线程不存在事务,则判断@TransactinalEventListener的fallbackExecution属性是否是true。若是true,则表示若当前线程没有正在运行事务运行,该监听器也会监听事件发布,运行processEvent方法调用方法处理事件。

3.4.4 若是当前线程不存在事务,且fallbackExecution属性为false,则不处理事件。

参考

https://www.jianshu.com/p/22b75f98ed16

分析事件监听器注解:@EventListener、@TransactionalEventListener相关推荐

  1. Java 创建事件Event、事件监听EventListener、事件发布publishEvent

    一.概述 个人认为,事件机制一般可由:事件源source,事件对象Event,事件监听EventListener,事件发布publishEvent组成 事件源:引起事件发生的源: User用户信息, ...

  2. 【spring】Spring事件监听器ApplicationListener的使用与源码分析

    ApplicationEvent以及Listener是Spring为我们提供的一个事件监听.订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性. ...

  3. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  4. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  5. java自定义监听器例子_Java使用自定义注解实现为事件源绑定事件监听器操作示例...

    本文实例讲述了Java使用自定义注解实现为事件源绑定事件监听器操作.分享给大家供大家参考,具体如下: 一 定义注解 import java.lang.annotation.*; import java ...

  6. SpringBoot源码初学者(二):SpringBoot事件监听器

    ps:真正适合阅读源码的新手来看的SpringBoot源码讲解,如果你真的想读懂SpringBoot源码,可以按照以下推荐的方式来阅读文章 打开ide,打开SpringBoot源码,跟着文章一起写注释 ...

  7. 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )

    文章目录 前言 一.创建 事件监听器 对应的 动态代理 二.动态代理 数据准备 三.动态代理 调用处理程序 四.动态代理 实例对象创建 前言 Android 依赖注入的核心就是通过反射获取 类 / 方 ...

  8. js事件监听器用法实例详解

    这篇文章主要介绍了js事件监听器用法,以实例形式较为详细的分析了javascript事件监听器使用注意事项与相关技巧,需要的朋友可以参考下 本文实例讲述了js事件监听器用法.分享给大家供大家参考.具体 ...

  9. 手写简版spring --10--容器事件和事件监听器

    一.降低耦合 解耦场景在互联网开发的设计中使用的也是非常频繁,如:这里需要一个注册完成事件推送消息.用户下单我会发送一个MQ.收到我的支付消息就可以发货了等等,都是依靠事件订阅和发布以及MQ消息这样的 ...

最新文章

  1. Hello,Expression Blend 4 (含Demo教程和源码)
  2. tushare pro接口_利用tushare获取新闻联播文字稿并制作词云
  3. java 类调用情况_java 如何调用类?情况如下
  4. c语言编程计算平分,用C语言编程平均分数
  5. 计算机的时间和dc的时间不同步_时间同步配置,让你轻松同步所有设备时间,让日志信息更有价值...
  6. CSUOJ 1111 三家人
  7. 阅读笔记——《R数据可视化手册》肖楠等;主要ggplot2
  8. windows10上Eclipse运行MapReduce wordcount程序遇到的坑
  9. 三极管工作原理_通俗易懂的讲解三极管工作原理,新手小白记得收藏
  10. 【干货#009】小程序如何格式化显示对象数组属性
  11. 全网最通俗易懂的爬虫教程
  12. 微信闪退Bug罪魁祸首竟是二维码引擎,附源代码分析
  13. 昆明新迎万枫、菏泽希尔顿花园酒店​开业;万豪在华运营酒店超过400家 | 中国酒店周刊...
  14. 含有使字的诗句_带有使字的诗-带有使字的诗句
  15. Mac - 通过 Script 实现更换桌面壁纸
  16. 零基础学C++Note
  17. 几种常见的通信系统抗衰落技术
  18. 科学摆放鼠标可以预防鼠标手
  19. Ubuntu 18.04安装Adams 2021
  20. VS如何引入数据库模型(Model)

热门文章

  1. python拼图_python – 组合实现和拼图
  2. C程序如何与操作系统交互?
  3. 学计算机的一直对画画感兴趣,小学生电脑绘画比赛总结.doc
  4. 设计院文件服务器,设计院制图规则及工作流程图纸.ppt
  5. 4个良心亲民的微信小程序,要是早点知道就好了!
  6. 基于intel平台车载M12网管交换机方案,13路网口,支持bypass功能
  7. nginx并发量优化
  8. 吃鸡2019年5月7日服务器维护,绝地求生12月19日7个半小时更新到几点 吃鸡更新维护公告...
  9. 前端学习之vue+element-ui电商项目(八)商品信息添加
  10. JVM面试题(史上最强、持续更新、推荐)