SpringBoot事件机制相关知识点汇总
要“监听”事件,我们总是可以将“监听器”作为事件源中的另一个方法写入事件,但这将使事件源与监听器的逻辑紧密耦合。
对于实际事件,我们比直接方法调用更灵活。我们可以根据需要动态注册和注销某些事件的侦听器。我们还可以为同一事件设置多个侦听器。
本教程概述了如何发布和侦听自定义事件,并解释了 spring boot 的内置事件。
为什么我应该使用事件而不是直接方法调用?
事件和直接方法调用都适合于不同的情况。使用方法调用,就像断言一样-无论发送和接收模块的状态如何,他们都需要知道此事件的发生。
对于事件,另一方面,我们只知道发生了一个事件,哪些模块会被通知并不是我们关心的问题。当我们想要将某些业务处理传递给另一个线程时(例如:在某些任务完成时发送电子邮件),最好使用事件。此外,事件对于测试驱动的开发也很有用。
什么是应用程序事件( application events)?
spring 应用程序事件允许我们发送和接收特定应用程序事件,我们可以根据需要处理这些事件。事件用于在松散耦合的组件之间交换信息。由于发布者和订阅者之间没有直接耦合,因此可以在不影响发布者的情况下修改订阅者,反之亦然。
让我们看看如何在 spring boot 应用程序中创建、发布和侦听自定义事件。
创建applicationevent
我们可以使用 spring framework 的事件发布机制发布应用程序事件。
让我们通过扩展来创建调用的自定义事件:
class usercreatedevent extends applicationevent { private string name; usercreatedevent(object source, string name) { super(source); this.name = name; } ... }
代码中super(source)中的source应该是最初发生事件的对象或与事件相关联的对象。
从spring 4.2开始,我们还可以将对象发布为事件,而无需扩展applicationevent:
class userremovedevent { private string name; userremovedevent(string name) { this.name = name; } ... }
发布一个applicationevent
我们使用applicationeventpublisher接口发布事件:
@component class publisher { private final applicationeventpublisher publisher; publisher(applicationeventpublisher publisher) { this.publisher = publisher; } void publishevent(final string name) { // publishing event created by extending applicationevent publisher.publishevent(new usercreatedevent(this, name)); // publishing an object as an event publisher.publishevent(new userremovedevent(name)); } }
当我们发布的对象不是applicationevent时,spring会自动为我们将其包装在payloadapplicationevent中。
接收应用程序事件
现在,我们知道如何创建和发布自定义事件,让我们看看如何侦听该事件。事件可以有多个侦听器并且根据应用程序要求执行不同的工作。
有两种方法可以定义侦听器。我们可以使用注解(@eventlistener)或实现接口(applicationlistener)。在这两种情况下,侦听器类都必须由 spring 管理。
注解
从spring 4.1开始,可以使用@eventlistener注解的方法,以自动注册与该方法签名匹配的applicationlistener:
@component class userremovedlistener { @eventlistener returnedevent handleuserremovedevent(userremovedevent event) { // handle userremovedevent ... return new returnedevent(); } @eventlistener void handlereturnedevent(returnedevent event) { // handle returnedevent ... } ... }
启用注解驱动的配置时,不需要其他配置。我们的方法可以监听多个事件,或者如果我们想完全不使用任何参数来定义它,那么事件类型也可以在注解本身上指定。示例:@eventlistener({contextstartedevent.class,contextrefreshedevent.class})。
对于使用@eventlistener注解并定义为具有返回类型的方法,spring会将结果作为新事件发布给我们。在上面的示例中,第一个方法返回的returnedevent将被发布,然后由第二个方法处理。
如果指定spel条件,spring仅在某些情况下才允许触发我们的侦听器:
@component class userremovedlistener { @eventlistener(condition = "#event.name eq 'reflectoring'") void handleconditionallistener(userremovedevent event) { // handle userremovedevent } }
仅当表达式的计算结果为true或以下字符串之一时才处理该事件:“ true”,“ on”,“ yes”或“ 1”。方法参数通过其名称公开。条件表达式还公开了一个“ root”变量,该变量引用原始applicationevent(#root.event)和实际方法参数(#root.args)
在以上示例中,仅当#event.name的值为'reflectoring'时,才会使用userremovedevent触发监听器。
实现applicationlistener接口
侦听事件的另一种方法是实现applicationlistener接口:
@component class usercreatedlistener implements applicationlistener<usercreatedevent> { @override public void onapplicationevent(usercreatedevent event) { // handle usercreatedevent } }
只要侦听器对象在spring应用程序上下文中注册,它就会接收事件。当spring路由一个事件时,它使用侦听器的签名来确定它是否与事件匹配。
异步事件侦听器
默认情况下,spring事件是同步的,这意味着发布者线程将阻塞,直到所有侦听器都完成对事件的处理为止。
要使事件侦听器以异步模式运行,我们要做的就是在该侦听器上使用@async注解:
@component class asynclistener { @async @eventlistener void handleasyncevent(string event) { // handle event } }
为了使@async注解起作用,我们还必须使用@enableasync注解我们的@configuration类之一或@springbootapplication类。
上面的代码示例还显示了我们可以将string用作事件。使用风险自负。最好使用特定于我们用例的数据类型,以免与其他事件冲突。
transaction-绑定事件
spring允许我们将事件侦听器绑定到当前事务的某个阶段。如果当前事务的结果对侦听器很重要时,这使事件可以更灵活地使用。
当我们使用@transactionaleventlistener注释方法时,我们将获得一个扩展的事件侦听器,该侦听器可以了解事务:
@component class userremovedlistener { @transactionaleventlistener(phase=transactionphase.after_completion) void handleafteruserremoved(userremovedevent event) { // handle userremovedevent } }
仅当当前事务完成时才调用userremovedlistener。
我们可以将侦听器绑定到事务的以下阶段:
after_commit:事务成功提交后,将处理该事件。如果事件侦听器仅在当前事务成功时才运行,则可以使用此方法。
after_completion:事务提交或回滚时将处理该事件。例如,我们可以使用它在事务完成后执行清理。
after_rollback:事务回滚后将处理该事件。
before_commit:该事件将在事务提交之前进行处理。例如,我们可以使用它来将事务性orm会话刷新到数据库。
spring boot的 application events
spring boot提供了几个与springapplication生命周期相关的预定义applicationevent。
在创建applicationcontext之前会触发一些事件,因此我们无法将这些事件注册为@bean。我们可以通过手动添加侦听器来注册这些事件的侦听器:
@springbootapplication public class eventsdemoapplication { public static void main(string[] args) { springapplication springapplication = new springapplication(eventsdemoapplication.class); springapplication.addlisteners(new springbuiltineventslistener()); springapplication.run(args); } }
通过将meta-inf/spring.factories文件添加到我们的项目中,我们还可以注册侦听器,而不管如何创建应用程序,并使用
org.springframework.context.applicationlistener键引用侦听器:
org.springframework.context.applicationlistener= com.reflectoring.eventdemo.springbuiltineventslistener
class springbuiltineventslistener implements applicationlistener<springapplicationevent>{ @override public void onapplicationevent(springapplicationevent event) { // handle event } }
确定事件监听器已正确注册后,便可以监听所有spring boot的springapplicationevents。让我们按照它们在应用程序启动过程中的执行顺序来进行观察。
applicationstartingevent
除了运行侦听器和初始化程序的注册之外,applicationstartingevent在运行开始时但在任何处理之前都会触发。
applicationenvironmentpreparedevent
当上下文中使用的环境可用时,将触发applicationenvironmentpreparedevent。
由于此时环境已准备就绪,因此我们可以在其他bean使用它之前对其进行检查和修改。
applicationcontextinitializedevent
当applicationcontext准备就绪并且调用applicationcontextinitializers但尚未加载bean定义时,将触发applicationcontextinitializedevent。
在bean初始化到spring容器之前,我们可以使用它来执行任务。
applicationpreparedevent
准备好apllicationcontext但未刷新时会触发applicationpreparedevent。
该环境已准备就绪,可以使用,并且将加载bean定义。
webserverinitializedevent
如果我们使用的是网络服务器,则在网络服务器准备就绪后会触发webserverinitializedevent。 servletwebserverinitializedevent和reactivewebserverinitializedevent分别是servlet和反应式网络服务。
webserverinitializedevent不扩展springapplicationevent。
applicationstartedevent
在刷新上下文之后但在调用任何应用程序和命令行运行程序之前,将触发applicationstartedevent。
applicationreadyevent
触发applicationreadyevent来指示该应用程序已准备就绪,可以处理请求。
建议此时不要修改内部状态,因为所有初始化步骤都将完成。
applicationfailedevent
如果存在异常并且应用程序无法启动,则会触发applicationfailedevent。在启动期间的任何时间都可能发生这种情况。
我们可以使用它来执行一些任务,例如执行脚本或在启动失败时发出通知。
结论
事件是为在同一应用程序上下文内的spring bean之间进行简单通信而设计的。从spring 4.2开始,基础结构已得到显着改进,并提供了基于注释的模型以及发布任意事件的功能。
英文原文:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
springBoot的事件机制GenericApplicationListener用法解析
-
spring-boot-2.0.3不一样系列之番外篇 - springboot事件机制,绝对有值得你看的地方
-
Android必备知识点之事件分发机制
-
Android必备知识点之View及View的事件分发机制
-
jQuery知识点(特殊属性,事件机制)学习
-
Android事件分发处理机制源码分析与知识点总结
-
springBoot的事件机制GenericApplicationListener用法解析
-
Lua中的函数相关知识点整理汇总
-
SpringBoot事件机制相关知识点汇总
-
Spring的事件机制知识点详解及实例分析