美文网首页Java架构技术栈
【戏说Spring Boot】Spring Boot监听器解析

【戏说Spring Boot】Spring Boot监听器解析

作者: 若丨寒 | 来源:发表于2020-05-04 22:22 被阅读0次

    监听器的注册方法

    【戏说Spring Boot】Spring Boot监听器解析

    好了,今天我们来说说 Spring Boot 的监听器,其实上一次给大家留了个坑,还记得下面这个构造方法吗?

    【戏说Spring Boot】Spring Boot监听器解析

    当时我们猜测 Listener 是否也和 Initializer 一样,事实上,注册监听器的过程是一样的,所以说用法和初始化器一模一样,但是我们今天的重点不是监听器的注册过程,而是监听器的实现机制。

    不过我觉得还是有必要列举一下监听器的使用。

    【戏说Spring Boot】Spring Boot监听器解析

    1、定义在 spring.factories 文件中,被 SpringFactoriesLoader 发现注册(工厂加载机制)

    【戏说Spring Boot】Spring Boot监听器解析

    注意到上面的红框,这里你必须填一个 ApplicationListener 的实现类,告诉 Spring 我只需要监听这一个事件,否则所有内置事件都会被监听到。

    配置工厂类

    【戏说Spring Boot】Spring Boot监听器解析

    2、 SpringApplication 初始化完成后手动添加

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    3、定义成环境变量,被 DelegatingApplicationListener 所发现注册(默认优先级最高)

    在配置文件中加入下面一行

    context.listener.classes=com.feichaoyu.springboot.initializer.ThirdInitializer
    
    【戏说Spring Boot】Spring Boot监听器解析

    上面的实现类都是实现 ApplicationListener 接口,不过还有一个接口 SmartApplicationListener

    听这名字就知道很牛逼

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    实现 SmartApplicationListener 接口的监听器可以同时监听多个你感兴趣的事件,而实现 ApplicationListener 接口只能监听一个事件。

    【戏说Spring Boot】Spring Boot监听器解析

    好了,监听器的使用就介绍到这了,下面开始重头戏了。

    引入监听器模型

    有请我们的 监听器模型 登场。

    【戏说Spring Boot】Spring Boot监听器解析

    监听器模型有四要素:

    • 事件
    • 监听器
    • 广播器
    • 事件触发机制

    我们通过用户下单的例子来说明这四个要素,这个例子非常重要,是你看懂 Spring Boot 监听器模型的关键。

    【戏说Spring Boot】Spring Boot监听器解析

    1、定义事件

    【戏说Spring Boot】Spring Boot监听器解析

    一旦有用户下单,则有一个短信事件,会给用户发送短信。还有一个积分事件,会给用户增加积分。

    2、定义事件监听器

    【戏说Spring Boot】Spring Boot监听器解析

    短信监听器只监听短信事件,积分监听器只监听积分事件,而对其他事件不感兴趣。

    3、定义事件广播器

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    首先,在 EventMulticaster 中定义了三个方法,分别是广播任务、添加监听器、移除监听器。

    接着, AbstractEventMulticaster 实现了 EventMulticaster 接口,重写了其中的三个方法,同时新增了两个方法,分别是广播前置任务和后置任务。在 multicastEvent 方法中,我们可以看到模板方法的使用,需要子类实现抽象父类。

    最后, OrderEventMulticaster 继承了 AbstractEventMulticaster ,重写了两个父类的方法。

    事件广播器中包含所有的监听器,会对所有监听器遍历,让监听器找到自己感兴趣的事件。

    4、事件触发机制

    【戏说Spring Boot】Spring Boot监听器解析

    我们还需要把监听器接口的三个实现类、广播器的接口的两个实现类通过 @Component 加入到 Spring 中,我上面没加,大家注意一下。

    然后把 AbstractEventMulticaster 的 listeners 变量加上 @Autowired ,让所有监听器的实现类注入进来。

    【戏说Spring Boot】Spring Boot监听器解析

    到此,这个例子写完了。

    可以测试一下,

    【戏说Spring Boot】Spring Boot监听器解析

    最终输出结果如下:

    【戏说Spring Boot】Spring Boot监听器解析

    那么在 Spring Boot 中,监听器的实现会不会也和上面的例子相似,为了证明我们的猜测,不妨去代码中找一下相关的类和接口呗,走你!

    【戏说Spring Boot】Spring Boot监听器解析

    Spring Boot 监听器模型解析

    我们同样也分四要素讨论。

    1、事件

    我们打开一个之前使用过的 ApplicationStartedEvent 事件类,查看 UML 图

    【戏说Spring Boot】Spring Boot监听器解析

    从图中我们看出, SpringApplicationEvent 就相当于我们的 OrderEvent , ApplicationStartedEvent 相当于 MessageEvent 、 CreditEvent 。

    2、监听器

    【戏说Spring Boot】Spring Boot监听器解析

    这个接口就相当于我们的 OrderListener 。我们之前通过实现该接口,自定义了一些监听器,Spring Boot 也内置了很多监听器,比如 DelegatingApplicationListener 。

    3、广播器

    广播器的层次结构和我们的也是一样的,可以对比来看

    【戏说Spring Boot】Spring Boot监听器解析

    4、事件触发机制

    和我们的 OrderRunListener 类似, EventPublishingRunListener 起到了相同的作用。具体我们下面分析。

    【戏说Spring Boot】Spring Boot监听器解析

    好了,下面我们开始研究代码。

    我们直接定位到这里

    【戏说Spring Boot】Spring Boot监听器解析

    run 方法点进去,由于方法太长,我分两次截取

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    注意到我所有的红框地方,也就是和监听器打交道的地方都列出来了,接下来我们就来分析一下。

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    进去看下

    【戏说Spring Boot】Spring Boot监听器解析

    知道为什么要有两个参数了吧,反射构造实例时需要传入的,和类型刚好对上了!

    getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); 这行代码很显然就是加载所有实现了 SpringApplicationRunListener 接口的类,不过Spring Boot 中默认只有一个实现类 EventPublishingRunListener 。

    这里我们关注一下 SpringApplicationRunListeners ,这个类是 SpringApplicationRunListener 的集合,从它的定义中也不难发现。

    【戏说Spring Boot】Spring Boot监听器解析

    它将获取到所有的实现了 SpringApplicationRunListener 接口的类。

    OK,我们回到 run 方法,继续向下看

    【戏说Spring Boot】Spring Boot监听器解析

    兄弟,我要进去了

    【戏说Spring Boot】Spring Boot监听器解析

    由于默认实现类是 EventPublishingRunListener ,因此我们下一步去它里面看看。

    【戏说Spring Boot】Spring Boot监听器解析

    用法和我们的相同,都是用过广播器去发布事件的,不过这个 initialMulticaster 是?

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    搜嘎,想起你来了。

    那我们继续进去看看吧

    【戏说Spring Boot】Spring Boot监听器解析

    resolveDefaultEventType 方法就是获取事件的 Class 类型。

    【戏说Spring Boot】Spring Boot监听器解析

    getApplicationListeners 这个方法值得我们 debug 一下。

    【戏说Spring Boot】Spring Boot监听器解析

    顺带问下,大家是否好奇这个 source 是啥?

    【戏说Spring Boot】Spring Boot监听器解析

    接着我们看下 ListenerCacheKey 这个实例。

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    也就是根据 event 类型和 source 类型构造出来的对象。

    实际上它是 AbstractApplicationEventMulticaster 的静态内部类。

    【戏说Spring Boot】Spring Boot监听器解析

    继续向下

    【戏说Spring Boot】Spring Boot监听器解析

    retrieverCache 变量的定义如下,它的键是 ListenerCacheKey ,值是 ListenerRetriever

    【戏说Spring Boot】Spring Boot监听器解析

    ListenerRetriever 其实也是 AbstractApplicationEventMulticaster 的内部类,用于存储监听器。

    【戏说Spring Boot】Spring Boot监听器解析

    第一次是没有缓存的,所以缓存中获取不到监听器,接着我们继续向下走

    【戏说Spring Boot】Spring Boot监听器解析

    这是个同步方法,我们进入 retrieveApplicationListeners 方法看看。

    【戏说Spring Boot】Spring Boot监听器解析

    这里就是获取之前添加的 listeners,从 this.defaultRetriever.applicationListeners 中来,那么这个里面的监听器是什么时候添加的呢?

    回去找找,不慌!

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    没错,就是这里了,我们之前也说过了,通过 getSpringFactoriesInstances 这个方法会构造出 SpringApplicationRunListener 的实现类,也是说默认的 EventPublishingRunListener ,然后传入参数构造出实例,同时创建一个 SimpleApplicationEventMulticaster 实例,由于监听器已经注册了,所以可以直接获取,把监听器列表加入 defaultRetriever

    【戏说Spring Boot】Spring Boot监听器解析

    OK,我们回到 retrieveApplicationListeners 方法,继续往下看

    【戏说Spring Boot】Spring Boot监听器解析

    点进去

    【戏说Spring Boot】Spring Boot监听器解析

    这里又出现一个类 GenericApplicationListenerAdapter ,从名字可以看出这是一个适配器类,用于将 ApplicationListener 适配成 GenericApplicationListener 。

    【戏说Spring Boot】Spring Boot监听器解析

    其中 GenericApplicationListenerAdapter 构造方法中,会采用泛型解析方法 resolveDeclaredEventType 将监听器感兴趣事件解析出来交给 declaredEventType 。

    也就是这一块内容

    【戏说Spring Boot】Spring Boot监听器解析

    然后判断该监听器是否支持 eventType 事件类型以及 sourceType 源类型。

    这里我们点进去看下

    【戏说Spring Boot】Spring Boot监听器解析

    首先会判断该监听器是否实现了 SmartApplicationListener ,如果是,那么会调用自己重写的 supportsEventType 方法,也就是我们之前写过的

    【戏说Spring Boot】Spring Boot监听器解析

    只要支持就返回 true,把该监听器加入 allListeners 中,最后返回。

    接着回到 getApplicationListeners 方法,将相应监听器列表放入缓存,然后返回所有对指定事件感兴趣的监听器。

    【戏说Spring Boot】Spring Boot监听器解析

    回到 multicastEvent 方法,开始触发对应监听器的监听事件方法。

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    高能来了!

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    至此,我们分析完了 listeners.starting() 的过程,那么其他过程几乎都是一样的。

    还记得我们的 run 方法吗?

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    整个红框的方法,就是监听器的整个生命周期。

    比如在 prepareEnvironment 时,调用了 listeners.environmentPrepared(environment)

    【戏说Spring Boot】Spring Boot监听器解析

    后续流程和 starting 时是类似的。

    到此我们的监听器机制也分析完了,实际上,Spring Boot 监听器模型用到了 观察者设计模式

    【戏说Spring Boot】Spring Boot监听器解析

    顺带列举一下 Spring Boot 监听方法与事件的对应关系:

    【戏说Spring Boot】Spring Boot监听器解析 【戏说Spring Boot】Spring Boot监听器解析

    来源:https://segmentfault.com/a/1190000022438530

    相关文章

      网友评论

        本文标题:【戏说Spring Boot】Spring Boot监听器解析

        本文链接:https://www.haomeiwen.com/subject/duyughtx.html