Spring注解驅(qū)動(dòng)之ApplicationListener異步處理事件說明
概述
之前我們講過簡(jiǎn)單使用ApplicationListener發(fā)布事件,處理事件,但是發(fā)現(xiàn)是同一個(gè)線程發(fā)送事件并自己處理事件的。
下面我們就來(lái)說下如何使用自定義的線程池來(lái)異步處理接收的事件。
示例
實(shí)現(xiàn)一個(gè)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í)行時(shí),先從容器中獲取name為applicationEventMulticaster的組件,如果獲取不到就好創(chuàng)建一個(gè)默認(rèn)的applicationEventMulticaster組件,該組件默認(rèn)是不會(huì)設(shè)置taskExecutor任務(wù)執(zhí)行器的,所以這里我們自定義一個(gè)設(shè)置了TaskExecutor的多波器,當(dāng)執(zhí)行initApplicationEventMulticaster方法從beanFactory中獲取applicationEventMulticaster組件時(shí),走getBean邏輯。
BeanFactory.getBean()邏輯是先從容器查看是否有該組件,如果沒有獲取該組件的定義,如果有定義就會(huì)創(chuàng)建一個(gè)組件返回并把組件保存到容器中。
測(cè)試用例
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(); } }
測(cè)試結(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
通過測(cè)試結(jié)果可以看出,main線程很快就返回了,而實(shí)際處理事件的線程是pool-1-thread-1,等待了3s多才返回。
ApplicationListener異步執(zhí)行源碼分析
參考:Spring注解驅(qū)動(dòng)之ApplicationListener用法
與上面同步執(zhí)行不同的地方就是使用了自定義的多波器里面的線程池執(zhí)行了事件處理。
多波器的獲取。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring 聲明式事務(wù)實(shí)現(xiàn)過程解析
這篇文章主要介紹了spring 聲明式事務(wù)實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10SpringBoot攔截器excludePathPatterns方法不生效的解決方案
這篇文章主要介紹了SpringBoot攔截器excludePathPatterns方法不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Springboot中PropertySource的結(jié)構(gòu)與加載過程逐步分析講解
本文重點(diǎn)講解一下Spring中@PropertySource注解的使用,PropertySource主要是對(duì)屬性源的抽象,包含屬性源名稱name和屬性源內(nèi)容對(duì)象source。其方法主要是對(duì)這兩個(gè)字段進(jìn)行操作2023-01-01Java中垃圾回收器GC對(duì)吞吐量的影響測(cè)試
這篇文章主要介紹了Java中垃圾回收器GC對(duì)吞吐量的影響測(cè)試,本文算是一個(gè)對(duì)垃圾回收器GC的優(yōu)化文章,需要的朋友可以參考下2014-09-09詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決
這篇文章主要介紹了詳解Intellij IDEA中.properties文件中文顯示亂碼問題的解決,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11DTO 實(shí)現(xiàn) service 和 controller 之間值傳遞的操作
這篇文章主要介紹了DTO 實(shí)現(xiàn) service 和 controller 之間值傳遞的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2021-02-02Spring?Boot項(xiàng)目如何優(yōu)雅實(shí)現(xiàn)Excel導(dǎo)入與導(dǎo)出功能
在我們平時(shí)工作中經(jīng)常會(huì)遇到要操作Excel的功能,比如導(dǎo)出個(gè)用戶信息或者訂單信息的Excel報(bào)表,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot項(xiàng)目中如何優(yōu)雅實(shí)現(xiàn)Excel導(dǎo)入與導(dǎo)出功能的相關(guān)資料,需要的朋友可以參考下2022-06-06windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝教程
這篇文章主要介紹了windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10