Spring注解驅(qū)動之ApplicationListener異步處理事件說明
概述
之前我們講過簡單使用ApplicationListener發(fā)布事件,處理事件,但是發(fā)現(xiàn)是同一個線程發(fā)送事件并自己處理事件的。
下面我們就來說下如何使用自定義的線程池來異步處理接收的事件。
示例
實(shí)現(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線程很快就返回了,而實(shí)際處理事件的線程是pool-1-thread-1,等待了3s多才返回。
ApplicationListener異步執(zhí)行源碼分析
參考:Spring注解驅(qū)動之ApplicationListener用法
與上面同步執(zhí)行不同的地方就是使用了自定義的多波器里面的線程池執(zhí)行了事件處理。

多波器的獲取。

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Security中的Servlet過濾器體系代碼分析
這篇文章主要介紹了Spring Security中的Servlet過濾器體系,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
Java Web開發(fā)項(xiàng)目中中文亂碼解決方法匯總
這篇文章主要為大家詳細(xì)匯總了Java Web開發(fā)項(xiàng)目中中文亂碼的解決方法,分析了5種Java Web中文亂碼情況,感興趣的小伙伴們可以參考一下2016-05-05
SpringBoot項(xiàng)目URL訪問異常的問題處理
這篇文章主要介紹了SpringBoot項(xiàng)目URL訪問異常的問題處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
Java 實(shí)戰(zhàn)項(xiàng)目之在線點(diǎn)餐系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)在線點(diǎn)餐系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11
一文搞懂MyBatis多數(shù)據(jù)源Starter實(shí)現(xiàn)
本文將實(shí)現(xiàn)一個MyBatis的Springboot的Starter包,引用這個Starter包后,僅需要提供少量配置信息,就能夠完成MyBatis多數(shù)據(jù)源的初始化和使用,需要的小伙伴可以參考一下2023-04-04
詳細(xì)解讀Druid數(shù)據(jù)庫連接池的使用
這篇文章主要介紹了Druid數(shù)據(jù)庫連接池的使用,數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而不是重新建立一個,需要的朋友可以參考下2023-03-03

