環境: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.www897cc.com/showinfo-26-76561-0.htmlSpring事件如何異步執行?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
下一篇: OpenFeign奪命連環九問