环境:SpringBoot2.7.16
ApplicationContext 中的事件处理是通过 ApplicationEvent 类和 ApplicationListener 接口提供的。如果在上下文中部署了实现 ApplicationListener 接口的 Bean,那么每次 ApplicationEvent 发布到 ApplicationContext 时,都会通知该 Bean。从本质上讲,这就是标准的观察者设计模式。
从Spring 4.2开始,事件基础设施得到了显著改进,并提供了基于注释的模型以及发布任意事件的能力(也就是说,不一定是从ApplicationEvent扩展的对象)。当这样的对象被发布时,我们将它包装在一个事件中。
以下是一个简单的事件应用
public class PackEvent extends ApplicationEvent { private static final long serialVersionUID = 1L; public PackEvent(Object source) { super(source); }}
@Componentpublic class PackEventListener implements ApplicationListener<PackEvent> { @Override public void onApplicationEvent(PackEvent event) { System.out.println("触发事件...") ; }}
@Resourceprivate ApplicationEventMulticaster eventMulticaster ;public void run(ApplicationArguments args) throws Exception { eventMulticaster.multicastEvent(new PackEvent("自定义Pack")) ;}
以上Spring事件系统的完整应用实例。在默认情况下该种事件处理方式是同步的,也就是事件的发布者与事件的处理都是同一个线程中,那这就要求我们的事件处理程序不应该处理复杂耗时的任务,否则会影响我们的主业务系统。那如何异步处理事件呢?
该种方式是最简单的方式了,开启异步功能,在基于注解的事件监听方法上使用@Async注解。
开启异步任务功能更
@EnableAsyncpublic class AppApplication {}
基于注解事件监听
@Async@EventListener({PackEvent.class})public void packEventListener(PackEvent event) { System.out.printf("%s - 事件发生了...%s%n", Thread.currentThread().getName(), event.getSource()) ;}
执行结果
task-1 - 事件发生了...自定义Pack
线程名已经变为了task-1。task-前缀是异步线程的默认名。关于异步任务执行应用的线程池配置,查看下面这篇文章。
Spring任务调度&异步任务&Web异步请求三者如何配置线程池?
上面是基于注解的方式应用异步执行事件处理。对于在简介中通过实现ApplicationListener接口的方式又该如何处理呢?
对于这种方式,我们可以通过两种方式进行处理:
@Componentpublic class PackEventListener implements ApplicationListener<PackEvent> { @Override public void onApplicationEvent(PackEvent event) { new Thread(() -> { System.out.printf("%s触发事件...%n", Thread.currentThread().getName()) ; }).start() ; }}
@BeanTaskExecutor taskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor() ; taskExecutor.setThreadNamePrefix("pack-event-") ; taskExecutor.setCorePoolSize(5) ; taskExecutor.setQueueCapacity(100) ; taskExecutor.setMaxPoolSize(5) ; taskExecutor.initialize() ; return taskExecutor ;}// 注意beanName必须为applicationEventMulticaster;下面的源码中你将看到@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)SimpleApplicationEventMulticaster eventMulticaster(BeanFactory beanFactory) { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(beanFactory) ; eventMulticaster.setTaskExecutor(taskExecutor()) ; return eventMulticaster ;}
通过这种方式也可以实现事件处理程序异步执行。而这种方式的实现原理如下:
容器启动中的核心方法refresh中
public abstract class AbstractApplicationContext { public void refresh() { // 初始化事件广播器 initApplicationEventMulticaster(); } protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 判断容器中是否存在beanName=applicationEventMulticaster if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); } else { // 如果不存在则创建一个同步的执行器。 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); } }}
以上是本篇文章的全部内容,希望对你有帮助。
完毕!!!
本文链接:http://www.28at.com/showinfo-26-76561-0.htmlSpring事件如何异步执行?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
下一篇: OpenFeign夺命连环九问