spring中@EventListener 的详解和使用

  • 1.1事件监听的基本原理
  • 1.2Spring中实现事件的模式
  • 1.3Spring事件的使用
  • 1.3.1首先自定义事件
  • 1.3.2监听器绑定事件
  • 1.3.2.1面向接口的方式
  • 1.3.2.2面向@EventListener注解方式
  • 1.3.3事件发布的方式
  • 1.3.4监听器支持排序功能
  • 1.5监听器的异步模式
  • 1.5.1用监听器的线程池实现异步
  • 1.5.2 用@Async在调用方法的时候实现
  • 1.6 源码分析


1.1事件监听的基本原理

首先了解下事件监听的基本原理,这里使用到的是设计模式中的“’'观察者模式"”模式。

spring listener运行时机_spring listener运行时机


举例说明

A是BCD三人的队长,今天他们4人要去执行一项任务。在开始之前队长已经分别将各个人任务分配下去,行动的时候只要队长A向各个队员发送统一的行动指令“行动”,当BCD接收到A的指令“行动”之后就马上去处理各自的任务。

这里的A就做为事件发布者,BCD三人监听A发送的指令做出相应的行动,整体的原理相对来说较为简单。

1.2Spring中实现事件的模式

事件相关的几个类

Spring中事件相关的几个类需要先了解一下,下面来个表格,将spring中事件相关的类和我们上面自定义的类做个对比,方便大家理解

spring listener运行时机_spring listener运行时机_02


事件对象event

表示所有事件的父类,内部有个source字段,表示事件源我们自定义的事件需要继承这个类。

事件监听器 listener

我们使用一个接口来表示事件监听器,是个泛型接口,后面的类型E表示当前监听器需要监听的事件类型,此接口中只有一个方法,用来实现处理事件的业务;其定义的监听器需要实现这个接口。

事件广播器 multicaster

负责事件监听器的管理(注册监听器&移除监听器,将事件和监听器关联起来)

事件发布multicastEvent

负责事件的广播(将事件广播给所有的监听器,对该事件感兴趣的监听器会处理该事件)

1.3Spring事件的使用

Spring为了简化事件的使用,提供了2种使用方式
面向接口的方式
面向@EventListener注解的方式

1.3.1首先自定义事件

spring listener运行时机_java_03

1.3.2监听器绑定事件

1.3.2.1面向接口的方式

spring listener运行时机_后端_04


原理

spring容器在创建bean的过程中,会判断bean是否为ApplicationListener类型,进而会将其作为监听器注册到AbstractApplicationContext#applicationEventMulticaster中,这块的源码在下面这个方法中,有兴趣的可以看一下

org.springframework.context.support.ApplicationListenerDetector#postProcessAfterInitialization

小结

从上面这个案例中可以看出,事件类、监听器类都是通过基于spring中的事件相关的一些接口来实现事件的功能,这种方式我们就称作面相接口的方式。

1.3.2.2面向@EventListener注解方式

spring listener运行时机_spring listener运行时机_05


原理

spring中处理@EventListener注解源码位于下面的方法中

org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated

EventListenerMethodProcessor实现了SmartInitializingSingleton接口,SmartInitializingSingleton接口中的afterSingletonsInstantiated方法会在所有单例的bean创建完成之后被spring容器调用,

1.3.3事件发布的方式

spring listener运行时机_spring_06

1.3.4监听器支持排序功能

spring listener运行时机_监听器_07

1.5监听器的异步模式

1.5.1用监听器的线程池实现异步

监听器的线程池的设置见 源码分析的5.6.4getTaskExecutor()

spring listener运行时机_spring listener运行时机_08

1.5.2 用@Async在调用方法的时候实现

spring listener运行时机_spring listener运行时机_09