SpringEvent源码解析
1.Spring Event简介
- Spring Event是设计模式中典型的——观察者模式。
- 定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于(观察)它的对象都会接收到通知,然后执行自身的业务。实现了业务间的松耦合。
- 观察者模式结构
-
被观察者
:类中有一个存放观察者集合的容器
。主要功能包含,向这个集合添加观察者,移除观察者,以及调用观察者。 -
观察者
:一般提供一个接口,在被观察者状态发生变化时触发。
-
- Spring Event核心结构即观察者模式的结构。
2.Spring Event主要类
- Spring Event主要类有三个:
- org.springframework.context.
ApplicationEvent
:事件,被观察者发布了什么样的事件,观察者观察什么样的事件,根据业务继承此类来实现,用来区分不同的监听者
。- ApplicationEvent继承JDK自带的
EventObject
,EventObject为所有事件类的父类。
- ApplicationEvent继承JDK自带的
- org.springframework.context.
ApplicationEventPublisher
:被观察者,通过这个类来实现对观察者的通知,告知(调用)观察者,我发布了这样的事件。 - org.springframework.context.
ApplicationListener
:观察者,观察对应的事件,在被观察者发布对应事件时,触发void onApplicationEvent(E event)
方法。- ApplicationListener 实现JDK自带的tag接口
EventListener
,EventListener无任何接口方法,只用来标志这个类的实现类是一个事件监听类。
- ApplicationListener 实现JDK自带的tag接口
- org.springframework.context.
- PS:如果要自己实现观察者模式,也可以参考Spring Event的模式,只要自己在实现的发布工具(
等同于ApplicationEventPublisher
)中,存储监听器的集合,然后在发布事件时,调用对应的监听器即可。 - 继承关系
- 实际应用中,被观察者通过类
ApplicationContext
进行事件的发布 - 实际应用中,通过实现
ApplicationListener
并指定监听的Event事件的实现观察者
- 实际应用中,被观察者通过类
3.源码分析
- 可能大家会疑惑,被观察者发布事件时,是怎样找到对应的监听器,并对其发起调用的呢?下面我们通过源码来分析。
- ApplicationContext——加载应用中的Spring监听器
- 通过下图,可以看到应用中ApplicationContext的实际实现是
GenericApplicationContext
。 - GenericApplicationContext的继承关系
- 在GenericApplicationContext的继承关系中,核心类为:
AbstractApplicationContext
-
AbstractApplicationContext
提供了一个addApplicationListener
的方法添加Spring容器中的所有ApplicationListener
的实现。 - 可以看到Spring容器加载时会将容器中的ApplicationListener的实现类添加到集合中。那这个方法是怎样触发的呢?
- 向上查找具体的方法调用方,可以查找到类:
EventListenerMethodProcessor
,该类实现的接口之一:SmartInitializingSingleton
,该接口的作用是在单例 bean
都初始化完成以后, 容器会回调该接口的方法afterSingletonsInstantiated
,就是在此方法中ApplicationListener添加到了集合中。
- 向上查找具体的方法调用方,可以查找到类:
- 虽然上图显示是,添加监听器到AbstractApplicationContext维护的私有属
性集合applicationListeners
中,但因为AbstractApplicationContext实现了接口ConfigurableApplicationContext
在容器初始化完成后,会调用refresh
方法,然后判断属性applicationEventMulticaster是否存在,不存在就新建一个,然后赋值给属性。这样后续ApplicationListener实现,都是添加到applicationEventMulticaster中。(没明白Spring这么做的原因????),因为在后面分析发布事件的时候,会发现最终进行发布的时候,还是会走ApplicationEventMulticaster
的方法multicastEvent
(多播
)。 - 通过上面的分析我们可以知道应用中的Spring监听器是如何加载到集合的。下面我们看下事件的发布。
-
- ApplicationContext——发布事件
- 从逻辑上来说,事件发布就是通过
ApplicationContext的publishEvent
方法,同步或异步
的调用存储在集合中ApplicationListener实例。 - 具体代码实现:org.springframework.context.support.
AbstractApplicationContext
#publishEvent
(java.lang.Object, org.springframework.core.ResolvableType) - 需要注意的是:我这里发布的事件,是在初始化加载的时候,添加到AbstractApplicationContext的私有属性
applicationListeners
中的监听器,但是最终他还是使用了org.springframework.context.event.SimpleApplicationEventMulticaster
#multicastEvent
(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)进行事件发布。(这就是让人比较奇怪的地方,如果有人知道为啥,麻烦留言告诉下
)。 - 通过上图可以看到,在获取到所有监听此事件(Event)监听器之后,进行遍历调用监听器。其中,如果系统配置了统一的
任务调度器
,就会使用配置的任务调度器异步调用,没有配置就会进行同步调用。 - 在invokeListener方法中,可以看到可以对指定的异常进行处理。只要配置了
ErrorHandler
实现类。
- 从逻辑上来说,事件发布就是通过
- 通过下图,可以看到应用中ApplicationContext的实际实现是
到此Spring Event源码分析就结束了,对于文中提到的异步执行,可以百度搜索。文中有什么描述错误的地方,欢迎大家指出,有什么问题,也可以留言交流。