Spring5源码 - 12 Spring事件监听机制_异步事件监听应用及源码解析

朱雀 2022-11-21 06:56 344阅读 0赞

文章目录

  • Pre
  • 实现原理
  • 应用
    • 配置类
    • Event事件
    • 事件监听 EventListener
    • 发布事件 publishEvent
  • 源码解析 (反推)
    • Spring默认的事件广播器 SimpleApplicationEventMulticaster#multicastEvent
    • 获取executor
    • 设置executor
    • 得出操作步骤
      • 方式一
      • 方式二
  • 其他开启异步的方式

在这里插入图片描述


Pre

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

在这里插入图片描述


实现原理

Spring提供的事件机制,默认是同步的。如果想要使用异步事件监听,可以自己实现ApplicationEventMulticaster接口,并在Spring容器中注册id为applicationEventMulticaster的Bean , 设置 executor 。

Spring会遍历所有的ApplicationListener, 如果 taskExecutor 不为空,这开启异步线程执行。

在这里插入图片描述


应用

配置类

  1. package com.artisan.eventlistener2;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.ComponentScan;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.event.ApplicationEventMulticaster;
  6. import org.springframework.context.event.SimpleApplicationEventMulticaster;
  7. import org.springframework.core.task.SimpleAsyncTaskExecutor;
  8. @Configuration
  9. @ComponentScan("com.artisan.eventlistener2")
  10. public class ArtisanConfig {
  11. @Bean(name = "applicationEventMulticaster") // Step1: id必须叫 applicationEventMulticaster
  12. public ApplicationEventMulticaster multicaster(){
  13. // Step2:实例化SimpleApplicationEventMulticaster
  14. SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
  15. // Step3:设置TaskExecutor
  16. simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
  17. return simpleApplicationEventMulticaster ;
  18. }
  19. }

Event事件

  1. package com.artisan.eventlistener2;
  2. import org.springframework.context.ApplicationEvent;
  3. public class ArtisanEvent extends ApplicationEvent {
  4. private String msg ;
  5. public ArtisanEvent(Object source) {
  6. super(source);
  7. }
  8. public ArtisanEvent(Object source,String msg) {
  9. super(source);
  10. this.msg = msg ;
  11. }
  12. public void print(){
  13. System.out.println(Thread.currentThread().getName() + "-----" + msg);
  14. }
  15. }

事件监听 EventListener

  1. package com.artisan.eventlistener2;
  2. import org.springframework.context.event.EventListener;
  3. import org.springframework.stereotype.Component;
  4. @Component
  5. public class ArtisanListenerByAnno {
  6. @EventListener(ArtisanEvent.class)
  7. public void onApplicationEvent(ArtisanEvent event) {
  8. System.out.println(Thread.currentThread().getName() + " EventListener 监听到ArtisanEvent.....");
  9. event.print();
  10. }
  11. }

发布事件 publishEvent

  1. package com.artisan.eventlistener2;
  2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3. public class ArtisanTest {
  4. public static void main(String[] args) {
  5. AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ArtisanConfig.class);
  6. // 模拟发布事件
  7. ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent"));
  8. System.out.println(Thread.currentThread().getName() + " over");
  9. }
  10. }

【结果】
在这里插入图片描述

如果我们把配置类中的

  1. @Bean(name = "applicationEventMulticaster")
  2. public ApplicationEventMulticaster multicaster(){
  3. SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
  4. simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
  5. return simpleApplicationEventMulticaster ;
  6. }

移除掉,重新运行

在这里插入图片描述

就变成了默认的同步监听了。。。。


源码解析 (反推)

Spring默认的事件广播器 SimpleApplicationEventMulticaster#multicastEvent

我们分析一下 ac.publishEvent(new ArtisanEvent("xxxx","msg from artisanEvent")); 最终会调用到

  1. org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)

在这里插入图片描述


获取executor

executor不为null则异步处理, 那看下executor = getTaskExecutor();

在这里插入图片描述

SimpleApplicationEventMulticaster的一个属性
在这里插入图片描述
在这里插入图片描述

那只要在实例化SimpleApplicationEventMulticaster的时候 set属性值就可以了哇。

所以现在的问题是什么时候给线程池属性赋值的问题?


设置executor

我们知道

  1. org.springframework.context.support.AbstractApplicationContext#refresh

在这里插入图片描述

看看 initApplicationEventMulticaster

  1. protected void initApplicationEventMulticaster() {
  2. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  3. //判断IOC容器中包含applicationEventMulticaster 事件多播器的Bean的name
  4. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  5. //创建一个applicationEventMulticaster的bean放在IOC 容器中,bean的name 为applicationEventMulticaster
  6. this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  7. if (logger.isDebugEnabled()) {
  8. logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  9. }
  10. }
  11. else { //容器中不包含一个beanName 为applicationEventMulticaster的多播器组件
  12. //创建一个SimpleApplicationEventMulticaster 多播器
  13. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  14. //注册到容器中
  15. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  16. if (logger.isDebugEnabled()) {
  17. logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
  18. APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
  19. "': using default [" + this.applicationEventMulticaster + "]");
  20. }
  21. }
  22. }

通过源码我们知道,Spring会先从容器中找 bean name 为 “applicationEventMulticaster” 的 bean,so问题就简单了,我们只要自定义个 bean name 为 applicationEventMulticaster 的 bean,并给其属性 taskExecutor 赋上自定义的线程池即可,这个时候就能实现异步事件处理了 .

得出操作步骤

所以,可以这么配置

方式一

  1. @Configuration
  2. @ComponentScan("com.artisan.eventlistener2")
  3. public class ArtisanConfig {
  4. @Bean(name = "applicationEventMulticaster")
  5. public ApplicationEventMulticaster multicaster(){
  6. SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster();
  7. simpleApplicationEventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
  8. return simpleApplicationEventMulticaster ;
  9. }
  10. }

方式二

或者写一个类实现 AbstractApplicationEventMulticaster ,仿照 SimpleApplicationEventMulticaster 即可

  1. package com.artisan.eventlistener2;
  2. import org.springframework.context.ApplicationEvent;
  3. import org.springframework.context.ApplicationListener;
  4. import org.springframework.context.event.AbstractApplicationEventMulticaster;
  5. import org.springframework.core.ResolvableType;
  6. import org.springframework.core.task.SimpleAsyncTaskExecutor;
  7. import org.springframework.core.task.TaskExecutor;
  8. import org.springframework.stereotype.Component;
  9. import java.util.Iterator;
  10. @Component("applicationEventMulticaster")
  11. public class AsyncApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
  12. private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
  13. public void setTaskExecutor(TaskExecutor taskExecutor) {
  14. this.taskExecutor = (taskExecutor != null ? taskExecutor : new SimpleAsyncTaskExecutor());
  15. }
  16. protected TaskExecutor getTaskExecutor() {
  17. return this.taskExecutor;
  18. }
  19. @Override
  20. @SuppressWarnings("unchecked")
  21. public void multicastEvent(final ApplicationEvent event) {
  22. }
  23. @Override
  24. public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
  25. for (Iterator<ApplicationListener<?>> it = getApplicationListeners().iterator(); it.hasNext();) {
  26. final ApplicationListener listener = it.next();
  27. System.out.println("-----------自定义异步事件监听-----------");
  28. getTaskExecutor().execute(() -> listener.onApplicationEvent(event));
  29. }
  30. }
  31. }

在这里插入图片描述


其他开启异步的方式

@EnbaleAsyn + @Async

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,344人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring事件监听机制

    前言 Spring中的事件机制其实就是设计模式中的观察者模式,主要由以下角色构成: 1. 事件 2. 事件监听器(监听并处理事件) 3. 事件发布者(发布事件...