javascript
Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析
文章目錄
- Pre
- 實現原理
- 應用
- 配置類
- Event事件
- 事件監聽 EventListener
- 發布事件 publishEvent
- 源碼解析 (反推)
- Spring默認的事件廣播器 SimpleApplicationEventMulticaster#multicastEvent
- 獲取executor
- 設置executor
- 得出操作步驟
- 方式一
- 方式二
- 其他開啟異步的方式
Pre
Spring5源碼 - 11 Spring事件監聽機制_源碼篇
實現原理
Spring提供的事件機制,默認是同步的。如果想要使用異步事件監聽,可以自己實現ApplicationEventMulticaster接口,并在Spring容器中注冊id為applicationEventMulticaster的Bean , 設置 executor 。
Spring會遍歷所有的ApplicationListener, 如果 taskExecutor 不為空,這開啟異步線程執行。
應用
配置類
package com.artisan.eventlistener2;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.core.task.SimpleAsyncTaskExecutor;@Configuration @ComponentScan("com.artisan.eventlistener2") public class ArtisanConfig {@Bean(name = "applicationEventMulticaster") // Step1: id必須叫 applicationEventMulticasterpublic ApplicationEventMulticaster multicaster(){// Step2:實例化SimpleApplicationEventMulticaster SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();// Step3:設置TaskExecutor simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());return simpleApplicationEventMulticaster ;}}Event事件
package com.artisan.eventlistener2;import org.springframework.context.ApplicationEvent;public class ArtisanEvent extends ApplicationEvent {private String msg ;public ArtisanEvent(Object source) {super(source);}public ArtisanEvent(Object source,String msg) {super(source);this.msg = msg ;}public void print(){System.out.println(Thread.currentThread().getName() + "-----" + msg);}}事件監聽 EventListener
package com.artisan.eventlistener2;import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;@Component public class ArtisanListenerByAnno {@EventListener(ArtisanEvent.class)public void onApplicationEvent(ArtisanEvent event) {System.out.println(Thread.currentThread().getName() + " EventListener 監聽到ArtisanEvent.....");event.print();} }發布事件 publishEvent
package com.artisan.eventlistener2;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class ArtisanTest {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ArtisanConfig.class);// 模擬發布事件ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent"));System.out.println(Thread.currentThread().getName() + " over");} }【結果】
如果我們把配置類中的
@Bean(name = "applicationEventMulticaster")public ApplicationEventMulticaster multicaster(){SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());return simpleApplicationEventMulticaster ;}移除掉,重新運行
就變成了默認的同步監聽了。。。。
源碼解析 (反推)
Spring默認的事件廣播器 SimpleApplicationEventMulticaster#multicastEvent
我們分析一下 ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent")); 最終會調用到
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)獲取executor
executor不為null則異步處理, 那看下executor = getTaskExecutor();
SimpleApplicationEventMulticaster的一個屬性
那只要在實例化SimpleApplicationEventMulticaster的時候 set屬性值就可以了哇。
所以現在的問題是什么時候給線程池屬性賦值的問題?
設置executor
我們知道
org.springframework.context.support.AbstractApplicationContext#refresh看看 initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();//判斷IOC容器中包含applicationEventMulticaster 事件多播器的Bean的nameif (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {//創建一個applicationEventMulticaster的bean放在IOC 容器中,bean的name 為applicationEventMulticasterthis.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isDebugEnabled()) {logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else { //容器中不包含一個beanName 為applicationEventMulticaster的多播器組件//創建一個SimpleApplicationEventMulticaster 多播器this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);//注冊到容器中beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isDebugEnabled()) {logger.debug("Unable to locate ApplicationEventMulticaster with name '" +APPLICATION_EVENT_MULTICASTER_BEAN_NAME +"': using default [" + this.applicationEventMulticaster + "]");}}}通過源碼我們知道,Spring會先從容器中找 bean name 為 “applicationEventMulticaster” 的 bean,so問題就簡單了,我們只要自定義個 bean name 為 applicationEventMulticaster 的 bean,并給其屬性 taskExecutor 賦上自定義的線程池即可,這個時候就能實現異步事件處理了 .
得出操作步驟
所以,可以這么配置
方式一
@Configuration @ComponentScan("com.artisan.eventlistener2") public class ArtisanConfig {@Bean(name = "applicationEventMulticaster")public ApplicationEventMulticaster multicaster(){SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());return simpleApplicationEventMulticaster ;}}方式二
或者寫一個類實現 AbstractApplicationEventMulticaster ,仿照 SimpleApplicationEventMulticaster 即可
package com.artisan.eventlistener2;import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.AbstractApplicationEventMulticaster; import org.springframework.core.ResolvableType; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.stereotype.Component;import java.util.Iterator;@Component("applicationEventMulticaster") public class AsyncApplicationEventMulticaster extends AbstractApplicationEventMulticaster {private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();public void setTaskExecutor(TaskExecutor taskExecutor) {this.taskExecutor = (taskExecutor != null ? taskExecutor : new SimpleAsyncTaskExecutor());}protected TaskExecutor getTaskExecutor() {return this.taskExecutor;}@Override@SuppressWarnings("unchecked")public void multicastEvent(final ApplicationEvent event) {}@Overridepublic void multicastEvent(ApplicationEvent event, ResolvableType eventType) {for (Iterator<ApplicationListener<?>> it = getApplicationListeners().iterator(); it.hasNext();) {final ApplicationListener listener = it.next();System.out.println("-----------自定義異步事件監聽-----------");getTaskExecutor().execute(() -> listener.onApplicationEvent(event));}} }其他開啟異步的方式
@EnbaleAsyn + @Async
總結
以上是生活随笔為你收集整理的Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring5源码 - 11 Sprin
- 下一篇: Spring5源码 - 13 Sprin