Spring事件
在本文中,我们将讨论如何在Spring中使用事件。
事件是框架中被忽视的功能之一,但也是非常有用的功能之一,并且像Spring中的许多其他能力一样,事件发布是ApplicationContext上下文提供的功能之一。
有一些简单的指导方案可供参考:
Spring允许创建和发布自定义事件,默认情况下是同步的,这具有一些优点,例如监听器能够参与发布者的业务上下文。
2.1:简单的应用程序事件
创建一个简单的事件类,只是一个存储事件数据的占位符,在这种情况下,事件类包含String消息:
public class CustomSpringEvent extends ApplicationEvent { private String message; public CustomSpringEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; } }
2.2:事件发布者
现在创建该事件的发布者,发布者构造事件对象并将其发布给正在收听的任何人。
要发布事件,发布者只需注入ApplicationEventPublisher并使用publishEvent() API:
@Component public class CustomSpringEventPublisher { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void doStuffAndPublishAnEvent(final String message) { System.out.println("Publishing custom event. "); CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message); applicationEventPublisher.publishEvent(customSpringEvent); } }
或者,发布者类可以实现ApplicationEventPublisherAware接口,这也将在应用程序启动时注入事件发布者,通常只需向@Autowire注入发布者就可以了。
2.3:事件监听器
最后,创建一个事件监听器,监听器的唯一要求是成为bean并实现ApplicationListener接口:
@Component public class CustomSpringEventListener implements ApplicationListener<CustomSpringEvent> { @Override public void onApplicationEvent(CustomSpringEvent event) { System.out.println("Received spring custom event - " + event.getMessage()); } }
需要注意的是,我们的自定义监听器如何使用泛型事件的泛型类型进行参数化,这使得onApplicationEvent()方法类型安全,也避免了必须检查对象是否是特定事件类的实例并将其强制转换。
并且,如前所述,默认情况下,spring事件是同步的,doStuffAndPublishAnEvent()方法将阻塞,直到所有监听器完成事件的处理。
在某些情况下,同步发布事件并不是我们想要的,我们可能需要异步处理我们的事件。
你可以通过使用执行程序创建ApplicationEventMulticaster bean来在配置中启用它; 对于我们的特殊诉求,简单线程池SimpleAsyncTaskExecutor能够运行良好:
@Configuration public class AsynchronousSpringEventsConfig { @Bean(name = "applicationEventMulticaster") public ApplicationEventMulticaster simpleApplicationEventMulticaster() { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor()); return eventMulticaster; } }
事件,发布者和监听器实现与以前保持一致,但现在,监听器将在一个单独的线程中异步处理事件。
Spring框架本身发布了很多开箱即用的事件,例如,ApplicationContext将触发各种框架事件:ContextRefreshedEvent,ContextStartedEvent,RequestHandledEvent等。
这些事件为应用程序开发人员提供了一个选择,提供一个钩子,将自己的自定义逻辑添加到应用程序和上下文的生命周期。
这是一个监听上下文刷新的监听器的示例:
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent cse) { System.out.println("Handling context re-freshed event. "); } }
从Spring 4.2开始,事件监听器不需要实现ApplicationListener接口
的bean,它可以通过@EventListener注解在托管bean的任何公共方法
上注册:
@Component public class AnnotationDrivenContextStartedListener { // @Async @EventListener public void handleContextStart(ContextStartedEvent cse) { System.out.println("Handling context started event."); } }
和前边一样,方法签名声明它消费的事件类型,并且这个监听器是同步调用的,但现在添加@Async注解就可以将其变成异步(不要忘记在应用程序中启用异步支持)。
也可以在事件类型中使用泛型信息派发事件。
6.1:通用应用事件
创建一个通用事件类型,在我们的示例中,事件类包含任何内容和成功状态:
public class GenericSpringEvent<T> { private T what; protected boolean success; public GenericSpringEvent(T what, boolean success) { this.what = what; this.success = success; } // ... standard getters }
注意GenericSpringEvent和CustomSpringEvent之间的区别,我们现在可以灵活地发布任何任意事件,并且不再需要从ApplicationEvent扩展。
6.2:监听器
现在创建一个该事件的监听器,我们可以通过像以前一样实现ApplicationListener接口来定义监听器:
@Component public class GenericSpringEventListener implements ApplicationListener<GenericSpringEvent<String>> { @Override public void onApplicationEvent(@NonNull GenericSpringEvent<String> event) { System.out.println("Received spring generic event - " + event.getWhat()); } }
但不幸的是,这个定义要求我们从ApplicationEvent类继承GenericSpringEvent,因此对于本篇文章,我们使用前面讨论过的注解驱动的事件监听器。
通过在@EventListener注解上定义布尔型SpEL表达式,也可以指定事件监听器。在这个案例中,只会为成功的String的GenericSpringEvent调用事件处理程序:
@Component public class AnnotationDrivenEventListener { @EventListener(condition = "#event.success") public void handleSuccessful(GenericSpringEvent<String> event) { System.out.println("Handling generic event (conditional)."); } }
6.3:发布事件
事件发布者与上述类似。但是由于类型擦除,我们需要发布一个事件来解析我们要过滤的泛型参数。例如,GenericStringSpringEvent类扩展了GenericSpringEvent<String>。
还有另一种发布事件的方式,如果我们从使用@EventListener注解的方法返回非null值作为结果,Spring框架将把该结果作为新事件发送给我们。 此外,我们可以通过在事件处理结果中将它们返回到集合中来发布多个新事件。
本段内容是关于使用@TransactionalEventListener注解,要了解有关事务管理的更多信息,spring事务相关资料。
从Spring 4.2开始,框架提供了一个新的@TransactionalEventListener注解,它是@EventListener的扩展,允许将事件的监听器绑定到事务的一个阶段。
绑定可以进行以下事务阶段:
这是事务事件监听器的简单示例:
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) public void handleCustom(CustomSpringEvent event) { System.out.println("Handling event inside a transaction BEFORE COMMIT."); }
仅当存在事件生成器正在运行且即将提交的事务时,才会调用此监听器。
并且,如果没有正在运行的事务,则根本不发送事件,除非我们通过将fallbackExecution属性设置为true来覆盖它。
总结
在这篇文章中,我们讨论了在Spring中处理事件的基础知识,创建一个简单的自定义事件,然后发布,最后在监听器中处理它。
我们还简要介绍了如何在配置中启用事件的异步处理。然后我们了解了Spring 4.2中引入的改进,例如注解驱动的监听器,更好的泛型支持以及绑定到事务阶段的事件。
本文分享自 PersistentCoder 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!