Spring注解驅(qū)動之ApplicationListener異步處理事件說明
概述
之前我們講過簡單使用ApplicationListener發(fā)布事件,處理事件,但是發(fā)現(xiàn)是同一個線程發(fā)送事件并自己處理事件的。
下面我們就來說下如何使用自定義的線程池來異步處理接收的事件。
示例
實現(xiàn)一個ApplicationListener用于處理事件
package com.atguigu.ext; import org.springframework.context.ApplicationListener; import org.springframework.context.PayloadApplicationEvent; import org.springframework.stereotype.Component; @Component public class MyApplicationListener implements ApplicationListener<PayloadApplicationEvent> { public void onApplicationEvent(PayloadApplicationEvent applicationEvent) { System.out.println("exe thread start:" + Thread.currentThread().getName() + ", time:" + System.currentTimeMillis()); System.out.println("收到事件:" + applicationEvent); System.out.println(applicationEvent.getPayload()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("exe thread end:" + Thread.currentThread().getName() + ", time:" + System.currentTimeMillis()); } }
自定義事件多波器
package com.atguigu.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.SimpleApplicationEventMulticaster; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @Configuration @ComponentScan("com.atguigu.ext") public class ExtConfig { @Bean public SimpleApplicationEventMulticaster applicationEventMulticaster() { SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>(1000); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS, blockingQueue); simpleApplicationEventMulticaster.setTaskExecutor(threadPoolExecutor); return simpleApplicationEventMulticaster; } }
之前看源碼可以發(fā)現(xiàn),在容器創(chuàng)建的refresh方法中的initApplicationEventMulticaster()方法執(zhí)行時,先從容器中獲取name為applicationEventMulticaster的組件,如果獲取不到就好創(chuàng)建一個默認(rèn)的applicationEventMulticaster組件,該組件默認(rèn)是不會設(shè)置taskExecutor任務(wù)執(zhí)行器的,所以這里我們自定義一個設(shè)置了TaskExecutor的多波器,當(dāng)執(zhí)行initApplicationEventMulticaster方法從beanFactory中獲取applicationEventMulticaster組件時,走getBean邏輯。
BeanFactory.getBean()邏輯是先從容器查看是否有該組件,如果沒有獲取該組件的定義,如果有定義就會創(chuàng)建一個組件返回并把組件保存到容器中。
測試用例
package com.atguigu; import com.atguigu.config.ExtConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * @Description : * @Version : V1.0.0 * @Date : 2022/9/1 15:07 */ public class AnnotationTest { public static void main(String[] args) { final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class); System.out.println("main thread start:" + Thread.currentThread().getName() + ", time:" + System.currentTimeMillis()); applicationContext.publishEvent("發(fā)送事件"); System.out.println("main thread end:" + Thread.currentThread().getName() + ", time:" + System.currentTimeMillis()); applicationContext.close(); } }
測試結(jié)果
main thread start:main, time:1663499481185
main thread end:main, time:1663499481188
exe thread start:pool-1-thread-1, time:1663499481188
收到事件:org.springframework.context.PayloadApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5ebec15: startup date [Sun Sep 18 19:11:20 CST 2022]; root of context hierarchy]
發(fā)送事件
九月 18, 2022 7:11:21 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5ebec15: startup date [Sun Sep 18 19:11:20 CST 2022]; root of context hierarchy
exe thread end:pool-1-thread-1, time:1663499484198
通過測試結(jié)果可以看出,main線程很快就返回了,而實際處理事件的線程是pool-1-thread-1,等待了3s多才返回。
ApplicationListener異步執(zhí)行源碼分析
參考:Spring注解驅(qū)動之ApplicationListener用法
與上面同步執(zhí)行不同的地方就是使用了自定義的多波器里面的線程池執(zhí)行了事件處理。
多波器的獲取。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot攔截器excludePathPatterns方法不生效的解決方案
這篇文章主要介紹了SpringBoot攔截器excludePathPatterns方法不生效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Springboot中PropertySource的結(jié)構(gòu)與加載過程逐步分析講解
本文重點講解一下Spring中@PropertySource注解的使用,PropertySource主要是對屬性源的抽象,包含屬性源名稱name和屬性源內(nèi)容對象source。其方法主要是對這兩個字段進(jìn)行操作2023-01-01詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決
這篇文章主要介紹了詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11DTO 實現(xiàn) service 和 controller 之間值傳遞的操作
這篇文章主要介紹了DTO 實現(xiàn) service 和 controller 之間值傳遞的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Spring?Boot項目如何優(yōu)雅實現(xiàn)Excel導(dǎo)入與導(dǎo)出功能
在我們平時工作中經(jīng)常會遇到要操作Excel的功能,比如導(dǎo)出個用戶信息或者訂單信息的Excel報表,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot項目中如何優(yōu)雅實現(xiàn)Excel導(dǎo)入與導(dǎo)出功能的相關(guān)資料,需要的朋友可以參考下2022-06-06windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝教程
這篇文章主要介紹了windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10