文章目录

  • 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. jquery的attr和prop区别之实例
  2. 基本数据结构和算法回顾
  3. NameError: name ‘sess‘ is not defined
  4. 致力协同办公oa系统服务器设置,致力协同办公oa系统安装手册新.pdf
  5. Linux入门(10)——Ubuntu16.04使用pip3和pip安装numpy,scipy,matplotlib等第三方库
  6. maven java1.7_本周Java技巧#7 – Maven慢吗?
  7. 一文聊“图”,从图数据库到知识图谱
  8. Spring4.x(7)---对象的生命周期方法
  9. oracle中的合并查询
  10. Python对Excel的操作(openpyxl)
  11. 为什么很多人已经很努力了
  12. 力扣 496 下一个更大的元素I
  13. 计算机网络连接图标 红叉,Win10网络图标显示红叉叉 检测不到网卡驱动解决方案...
  14. MYSQL数据库日志
  15. 用云真机测试本地应用程序
  16. verilog源码积累:ram和axi slaver
  17. php毕设代做,客户管理系统,java,jsp,php,好毕设为你指导如何完成一个客户管理系统...
  18. quartz定时器时间设置规则
  19. Qt 之格栅布局(QGridLayout)
  20. 【转自BYR】慎思而行——对选择工作的建议

热门文章

  1. Android自定义View实践 空气质量检测 pm2.5
  2. java对一个无序列表进行分组
  3. (FCN)-Fully Convolutional Networks for Semantic Segmentation
  4. python3是unicode还是utf-8_ASCII、Unicode、UTF-8以及Python3编码问题
  5. rxjava获取异步请求的结果_我为什么不再推荐用 RxJava
  6. Leetcode 144. 二叉树的前序遍历 (每日一题 20210820)
  7. 机器学习的发展和硬件发展的关系
  8. tableau实战系列(二十八)-以可视化的方式打开关联分析算法购物篮分析(Market Basket Analysis)
  9. MATLAB table数据结构 首篇
  10. 电压越低采集的ad值反而变大_80多条关于AD转换设计的经验总结