spring-event

183 阅读3分钟

一、什么是event

event即事件,是一种观察者设计模式的一种实现,使用事件机制可以将相互耦合的代码解耦,从而方便功能的修改与添加。

举个例子,假设有一个审批的方法,比如审核通过,需要初始化下一个流程相关业务逻辑、给用户发送通知消息、写入变更历史表、发送消息到消息队列等1+n子流程操作。

  1. ApplicationEvent(事件源):表示事件本身,自定义事件需要继承该类,可以用来传递数据
  2. ApplicationEventPublisher(事件发布器):用于发送事件源。
  3. ApplicationListener(事件监听器):事件的业务逻辑封装在监听器里面。

image.png

二、使用

2.1 事件定义

2.1.1 继承

类继承ApplicationEvent,将需要传递的事件信息包装为业务事件类。

image.png

2.1.2 直接定义

直接使用定义的类来做为业务事件类。

image.png

2.2 事件发布

2.2.1 ApplicationEventPublisher

注入ApplicationEventPublisher事件发布器,通过publishEvent方法即可发布事件。

image.png

2.2.2 ApplicationContext 

注入ApplicationContext(spring上下文),继承ApplicationEventPublisher,也可以调用publishEvent方法即可发布事件。

image.png

2.3 事件监听

事件监听生效的bean必须在spring容器里。

2.3.1 继承ApplicationListener

实现对应事件的监听器,需要继承ApplicationListener,并实现onApplicationEvent方法,通过泛型指定需要监听的事件类。

image.png

2.3.2 使用@EventListener注解

使用@EventListener注解方法,将其包装为事件处理器。它适用于:

  1. 不想为每个事件处理都创建一个ApplicationListener实现类。
  2. 希望支持更复杂的事件条件过滤。@EventListener的classes属性可以过滤事件类型,而condition属性可以根据事件对象是否满足条件表达式来过滤事件。

image.png

2.3.3 使用@TransactionalEventListener注解

继承@EventListener,用于不希望事件在发布的时候就立马执行,而是与事务的某个阶段进行绑定。比如事务提交前发送了MQ,别的系统监听到后再来查后发现不满足他们的执行规则,或者在做一些其他操作(短信通知)并不希望失败后影响原有业务流程的一个正常运转。

@TransactionEventListener允许事件处理方法感知事务。它的phase属性,表示希望在事务的哪个阶段执行事件处理。当在事务环境下(@Transactional 注解),发送事件时,如果使用TransactionalEventListener监听事件,那么默认情况下会延迟到事务已提交之后才开始执行。这样避免在后续操作出错、导致事务回滚的情况下,事件已经被处理,无法撤回。

image.png

2.4 异步处理

默认情况下,ApplicationListener处理事件是同步执行的。

2.4.1 自定义ApplicationEventMulticaster

image.png

所有Listener都是异步执行。

2.4.2 手动提交线程池异步执行

image.png 代码侵入性较高

2.4.3  使用@Async 注解

对于@EventListener注解的方法处理器,可以使用@Async注解,使得方法调用变为异步调用。(需要在启动类Application上使用@EnableAsync注解,引入对@Async的支持。)

image.png

三、 原理

3.1 事件原理

image.png

注:事件是发布是广播形式,所有监听此事件的类型都会执行,使用时要注意监听重复,代码执行多次。

3.2 注解原理

image.png

3.3 @TransactionalEventListener执行原理

image.png

四、总结

  • Spring-Event使用ApplicationEventPublisher发布事件,通过实现ApplicationListener监听事件,这种模式可以解耦复杂的业务依赖。用@EventListener或@TransactionalEventListener注解来处理,可以提供更复杂的条件过滤,或者事务状态感知,支持业务实现更复杂的事件处理。
  • 从源码实现方面,AbstractApplicationContext在refresh过程中初始化ApplicationEventMulticaster(SimpleApplicationEventMulticaster)和ApplicationListener,并向ApplicationEventMulticaster注册监听器。这样在发布事件后,ApplicationEventMulticaster能够找到类型匹配的ApplicationListener,并执行调用。
  • 对于@EventListener或@TransactionalEventListener,则依赖方法处理器EventListenerMethodProcessor遍历所有bean并找出被注解的方法,用对应的EventListenerFactory(DefaultEventListenerFactory或者TransactionalEventListenerFactory)将该方法包装为ApplicationListener。对于@TransactionalEventListener来说,需要额外通过事务同步器感知事务状态变动。