Spring 事件发布
孙玉超
2020-10-14 15:12:37
0 评论
911 浏览
0 收藏
0 赞
其实在学校的时候就接触过事件,比如学古老的 Swing 时,那些按钮的监听,文本框的监听等等。再比如后来学习网页的时候,按钮的监听,文本框,鼠标等监听。这些监听和事件发布类似,它们需要三个关键要素。
事件源、事件和监听器。事件是框架中最容易被忽视的功能之一,但同时也是一个很有用的功能。像Spring其他特性一样,事件发布是 ApplicationContext 提供的功能之一。
事件通知是一个很有用的功能,使用事件机制可以将互相耦合的代码进行解耦,方便功能的新增或修改。
同步事件监听
首先定义一个类继承 ApplicationEvent 作为我们的事件类,然后在 Service 层写一个方法进行事件发布,也就是我们的事件源。Spring 使用 ApplicationEventPublisher 类来进行事件的发布 。 然后在当前 Service 或者其他 Service 再定义一个监听方法来监听我们的事件,代码如下:
//事件类 public class TestEvent extends ApplicationEvent { @Getter private final transient String str; public TestEvent(Object source , String str) { super(source); this.str = str; } } //事件源(此方法写在业务层) public void test1(){ applicationEventPublisher.publishEvent(new TestEvent(this,"sunyuchao")); } //事件监听(此方法写在业务层) @EventListener(TestEvent.class) public void testListen1(TestEvent testEvent){ log.info(testEvent.getStr()); }
上面代码就是最简单的一个同步事件发布,在我目前接触的案例,事件类主要是用来传递数据,然后在监听方法中去做我们的业务处理。
异步事件监听
Spring 事件还支持异步事件,只需要在监听器上加上 @Async 注解,SpringBoot 主启动类加上 @EnableAsync 注解就可以生效。
当使用异步事件监听时,需要注意以下限制:
- 如果异步事件监听器抛出 Exception ,不会将其传播到调用方。可以查看 AsyncUncaughtExceptionHandler 来获取更多详细信息。
- 异步事件监听方法无法通过返回值来发布后续事件。如果你确实需要发布后续事件,可以注入 ApplicationEventPublisher 来手动发布。
事务事件监听
这是应用最多的场景,一般我们 Service 层都是带事务的,当使用事务监听器时,首先事件源方法也就是发布事件的那个方法需要用 @Transactional 来修饰,其次监听器的注解不再使用@EventListener,而是@TransactionalEventListener。
@TransactionalEventListener 是对 @EventListener的 一个扩展,允许将事件的监听器绑定到事务的某个阶段。可以绑定到以下事务阶段:
- AFTER_COMMIT (默认),事务提交后
- AFTER_ROLLBACK ,事务回滚后
- AFTER_COMPLETION ,事务完成,包括提交后和回滚后
- BEFORE_COMMIT ,事务提交前
例如写监听器的时候可以这样写,@TransactionalEventListener(classes = TestEvent.class,phase = TransactionPhase.AFTER_COMMIT) 来控制在事务提交之后再执行监听事件。
注意自己测试的时候要引入数据库依赖,配置数据源。否则事务监听不会生效,博主当时就是因为这个莫名其妙,排查了好久,最后还是同事大佬给我定位到的问题……没有数据库的话,它默认 Service 层加 @Transactional 注解是不会生效事务的。另外如果使用 @TransactionalEventListener 注解,那么原来的 service 方法必须要加事务控制 @Transactional 注解,否则也不生效!