SpringEvent源码解析

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

到此Spring Event源码分析就结束了,对于文中提到的异步执行,可以百度搜索。文中有什么描述错误的地方,欢迎大家指出,有什么问题,也可以留言交流。