Spring事务监听器@TransactionalEventListener 源码解析

使用实例

监听器:

@Component
public class TransactionListener {

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handler(TransactionEvent transactionEvent) {
        System.out.println(transactionEvent.getSource());
    }
}

带有事务的业务代码:

@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public void saveUser() {
    User user = new User();
    userMapper.insert(user);
    eventPublisher.publishEvent(newTransactionEvent("事务提交后发布事件1"));
}

源码:

TransactionalEventListenerFactory:

作用:

这个类用来创建ApplicationListenerMethodTransactionalAdapter对象


image
如何被注册到spring容器中

@Bean的方式
AbstractTransactionManagementConfiguration这个类被@Configuration修饰


image

下面有个@Bean的方法,创建出TransactionalEventListenerFactory实例


image

EventListenerMethodProcessor

在AnnotationConfigUtils.registerAnnotationConfigProcessors()方法中会把这个类弄成BeanDefinition,注册到BDRegistry中

image

这个类实现EventListenerMethodProcessor接口的postProcessBeanFactory方法,和BeanFactoryPostProcessor接口的afterSingletonsInstantiated(),其他Bean实例化过程中会调用到这两个方法

image

创建监听器

在所有bean实例化之后,实现SmartInitializingSingleton接口的Bean,会被调用到实现该接口的
afterSingletonsInstantiated方法。

DefaultListableBeanFactory.preInstantiateSingletons()

image

这里EventListenerMethodProcessor调用afterSingletonsInstantiated方法


image

从BeanFactoryBean取出所有的BeanName,循环调用processBean方法

image

processBean方法

从bean的Class对象中找出含有@EventListener注解的方法,存到Map<Method, EventListener>中,
@TransactionListenr方法也会被匹配,因为这个注解里打了@EventListener

image

如果从Bean的Class对象中,找到了含有@EventListener注解的方法,循环每一个方法,循环调用EventListenerFactory的子类进行,判断是否支持该方法的上的注解

//策略模式,如果支持解析该方法的注解,则调用该factory的createApplicationListener方法创建监听器

  1. TransactionalEventListenerFactory 用来对@TransactionalEventListener修饰的方法创建监听器


    image
  2. DefaultListenerFactory 用来对@EventListener,@TransactionalEventListener修饰的方法创建监听器

image
创建ApplicationListenerMethodTransactionalAdapter对象
image

其构造方法将beanName,Class,method对象,赋值到自己的属性中,并把注册抽出来了而已

image

创建完监听器对象后,将其加入到Spring的事务管理器中


image

ApplicationListenerMethodTransactionalAdapter类

image

实现了ApplicationListener接口,说明它是一个监听器,前面已经加入到事件管理器中,那么根据实现的onApplicationEvent方法的参数类型,决定响应不同类型的事件

image

那么,我们编写的带有@TransactionalEventListener注解的方法会在发布事件之后,就会被调用么?

发布事件

注入ApplicationEventPublisher对象

这就是一个上下文ApplicationContext对象,ApplicationContext实现了ApplicationEventPublisher接口

@Autowired
private ApplicationEventPublisher eventPublisher;

发布事件:

image
image

根据时间类型,拿出事件管理器里的监听器,执行onApplicationEvent方法

image

这个到ApplicationListenerMethodTransactionalAdapter来执行onApplicationEvent方法

image
image
image

创建一个了TransactionSynchronization对象,放到了事务管理器中
TransactionSynchronization

  1. 里面持有:event对象
  2. 由被@TransactionalEventListener修饰的方法封装而成的监听器适配器
  3. @TransactionalEventListener的value值(TransactionPhase.AFTER_COMMIT)
image

发布事件的话,后面就没了,那么事件的触发在哪里呢?在事务的切面里。

事务提交后,触发事件

事务切面

提交事务后,会调这个方法

image

取出存放在TransactionSynchronizationManager事务管理器中的TransactionSynchronization,刚才发布事件的时候,往里面存了的哦

image
image

分别调用TransactionSynchronization对象的afterCompletion方法

image
image
image

最后从容器中取出我们编写的TransactionListener类型的bean,反射调用它的被@TransactionalEventListener修饰的方法

image
image

总结

一般的监听器

  1. 实现ApplicationListener接口,实现onApplicationEvent方法,
  2. 用@Componnet修饰,ioc容器启动的时候加入到事件管理器中,获取手动调用上下文对象的addApplicationListener方法加入
  3. 发布事件,随即触发事件

@TransactionalEventListener修饰的监听器

  1. 每一个被该注解修饰的方法都会创建一个监听器(持有method对象和当前类的Class),并加入到事件管理器中
  2. 发布事件时,调用上一步创建的监听器的监听方法,将该监听器和必要的信息封装成对象,放到事务管理器
  3. 由事务切面在提交事务之后,从事务管理器里取出上一步存储的对象,反射调用我们自己的监听方法。
需注意点:
  1. 事务监听方法所在的类一定要注册到spring容器中,如果没被实例化,则不会判断方法中是否存在@TransactionalEventListener注解,不会创建监听器适配器。
  2. 发布事件一定要在被事务管理的代码中。如果在事务范围之外发布事件,事务切面已经结束,则不会去调用监听器适配器中反射调用我们监听方法的方法。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容