文章目录

  • 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事件监听机制_异步事件监听应用及源码解析相关推荐

  1. Spring5源码 - 13 Spring事件监听机制_@EventListener源码解析

    文章目录 Pre 概览 开天辟地的时候初始化的处理器 @EventListener EventListenerMethodProcessor afterSingletonsInstantiated 小 ...

  2. Spring5源码 - 11 Spring事件监听机制_源码篇

    文章目录 pre 事件监听机制的实现原理[观察者模式] 事件 ApplicationEvent 事件监听者 ApplicationEvent 事件发布者 ApplicationEventMultica ...

  3. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  4. Spring5源码 - 10 Spring事件监听机制_应用篇

    文章目录 Spring事件概览 事件 自定义事件 事件监听器 基于接口 基于注解 事件广播器 Spring事件概览 Spring事件体系包括三个组件:事件,事件监听器,事件广播器 事件 Spring的 ...

  5. java监听机制_详解java的事件监听机制和观察者设计模式

    首先说说监听器: 监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执 行. java的事件监 ...

  6. java判断麻将听牌_和牌看听:麻将听牌种类大全

    所谓听牌是指什么而言,大家想必已大致明白了吧. 麻将是四个人进行的比赛.A.B.C三位好友在茶馆里饮茶,有人说了: "好不容易咱们三个才凑在一起,打打麻将多好,可惜还差一个人,没法打呀!&q ...

  7. Java中事件监听机制

    Java中事件监听机制 一.事件监听机制的定义 要想了解Java中的事件监听机制,首先就要去了解一下在Java中事件是怎样去定义的呢!在使用Java编写好一个界面后,我们就会对界面进行一些操作,比如, ...

  8. Apache ZooKeeper - 事件监听机制详解

    文章目录 事件监听机制命令 Zookeeper事件类型 实操 -w get -w /path 监听节点数据的变化 ls -w /path 监听子节点的变化(增,删) [监听目录] ls -w /pat ...

  9. 探究react的事件机制(合成事件)

    一.react的事件机制 react自身实现了一套事件机制,包括事件的注册.事件的存储.事件的合成及执行等. react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上,然后 ...

最新文章

  1. “别人家的小孩”是如何用一行代码手撕面试题的?
  2. Smack Component 多线程环境下的问题解决
  3. 外网win10 64位环境下 为内网win7 32位安装三方包的最靠谱手段:python64位、32位全安装。...
  4. 解决配置Ubuntu中vnc远程显示灰屏
  5. python 动漫卡通人物图片大全_用Python把人物头像动漫化,不同的表情给你不同的惊喜...
  6. 【性能测试】性能测试的基础理论
  7. 程序设计实验与上机考试教程 全国计算机等级考试二级vb模拟试题,程序设计基础实验与上机考试教程...
  8. android路由是什么意思,不能跑Android的路由不是好路由
  9. Okhttp3用法案例:查询小车余额
  10. Wix学习整理(6)——安装快捷方式
  11. Linux 4.16 正式发布:不再支持 8 种 CPU 架构,内核减少了 450000 行代码 !
  12. 工控安全| 西门子S7-300攻击分析
  13. php 将录音转化成文字,录音转文字助手app下载 录音转文字助手(语音转文字/在线翻译)for android V4.8.2 安卓免费版 下载-脚本之家...
  14. 各种文件后缀名与打开方式大全
  15. 【FTP】apache FTP Server使用过程中遇到的问题
  16. amazon - FileZilla 连接 amazon云服务器
  17. dz邮箱验证怎么设置_如何设置discuz qq邮箱验证
  18. 排行前50的编程语言
  19. 网易2018校招内推笔试-彩色砖块
  20. 什么是市盈率,它和股票价格有什么关系?

热门文章

  1. java中que_重写java Eques()方法-不工作吗?
  2. ipad鼠标圆圈变成箭头_【附视频指南】iPad 只能刷剧?来看看我是如何把它武装成生产力工具的!...
  3. python super 参数问题
  4. 2. Leetcode 167. 两数之和 II - 输入有序数组 (数组-双向双指针)
  5. 找到指定的新类型字符
  6. 语音识别(一):特征抽取~1.1 抽样(sampling)和量化(quantization)
  7. 报错整理:ImportError: cannot import name ‘mean_absolute_percentage_error‘ from ‘sklearn.metrics‘
  8. Matlab在概率统计中的应用问题及解决方案集锦
  9. 用Tableau画延展条形图(Extended Bar Chart)
  10. 获取相册所有uri_URI转码