likes
comments
collection
share

SpringBoot ApplicationListener原理解析

作者站长头像
站长
· 阅读数 33

前言

示例

新建一个ReadyListener

package geek.springboot.application.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;

/**
 * 监听{@link ApplicationReadyEvent}事件
 *
 * @author Bruse
 */
@Slf4j
public class ReadyListener implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info(" application is ready");
    }

}

注册ReadyListener

package geek.springboot.application;

import geek.springboot.application.listener.ReadyListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@Slf4j
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        // 声明SpringApplication
        SpringApplication application = new SpringApplication(Application.class);
        // 注册监听器
        application.addListeners(new ReadyListener());
        // 启动SpringApplication
        application.run(args);
    }

}

启动输出如下

SpringBoot ApplicationListener原理解析

源码分析

关联关系

SpringApplication.listeners

因为是调用SpringApplicationaddListeners()方法进行注册器监听的,所以首当其冲地查看该方法实现,发现注册监听器不过是往SpringApplicationlisteners(监听器列表)中添加监听器而已。

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

setter就有getter,那么再去查看调用该变量的地方有哪些

SpringBoot ApplicationListener原理解析

EventPublishingRunListener

接着找到了EventPublishingRunListener,从注释可以看出这个类会通过使用内部的ApplicationEventMulticaster进行事件处理。

SpringBoot ApplicationListener原理解析

为了印证猜想,打上断点并启动,可以看到不止是自定义的ReadyListener实例,还有一些ApplicationListener实例也被添加到了initialMulticaster中。

SpringBoot ApplicationListener原理解析

EventPublishingRunListener如何初始化的

接下来查看该构造函数的调用地方,结果却是没有代码引用

SpringBoot ApplicationListener原理解析

换成按类名搜索引用的话,可以看到EventPublishingRunListener其实是在META-INF/spring.factories中进行注册的,它会被SpringFactoriesLoader扫描并进行初始化

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

SpringApplicationRunListener

与此同时还看到其实EventPublishingRunListener实现了SpringApplicationRunListener接口,由注释可以看到它是一个SpringApplication运行方法的监听器,而且它也是由SpringFactoriesLoader加载的。

SpringBoot ApplicationListener原理解析

SpringApplicationRunListeners

那么查找接口的引用,顺着找到原来是SpringApplicationRunListeners在引用,由注释也可以看出它其实算是包装了SpringApplicationRunListener实现的集合。

SpringBoot ApplicationListener原理解析

SpringApplicaiton.getRunListeners()

再次查找SpringApplicationRunListeners的引用,找到了SpringApplication.getRunListeners()方法

SpringBoot ApplicationListener原理解析

顺藤摸瓜,可以看出在调用SpringApplicationrun()方法时,就已经初始化并获取了SpringApplicationRunListeners实现,其包含了所有SpringApplicationRunListener接口实现,也就包含了EventPublishingRunListener,而它内部又是依靠SimpleApplicationEventMulticaster处理所有ApplicationListener事件监听。

SpringBoot ApplicationListener原理解析

那么我们可以得出清晰的调用链路或者说关联关系

SpringApplication ——> SpringApplicationRunListeners ——> SpringApplicationRunListener | EventPublishingRunListener ——> SimpleApplicationEventMulticaster ——> ApplicationListener

事件分发

因为自定义的ReadyListener关注的是ApplicationReadyEvent事件,那么直接从SpringApplicationRunListenersready()方法开始切入。

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

逐个遍历SpringApplicationRunListener并调用其ready()方法

SpringBoot ApplicationListener原理解析

来到EventPublishingRunListenerready()方法,声明了一个ApplicationReadyEvent事件,并交由ApplicationContext进行事件推送。

SpringBoot ApplicationListener原理解析

但其实一步步往下执行,你会发现最终其实也还是交给SimpleApplicationEventMulticastermulticastEvent()方法进行处理。

SpringBoot ApplicationListener原理解析

multicastEvent()

可以看到multicastEvent()方法,其实就是获取当前对ApplicationReadyEvent事件感兴趣的ApplicationListener,然后逐个调用其onApplicationEvent()方法。

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

获取ApplicationListener

getApplicationListeners()

深入一下getApplicationListeners()方法实现,可以看到该方法其实是返回与给定事件类型匹配的ApplicationListener集合,因为在前面调用EventPublishingRunListenerready()方法时,声明的是ApplicationReadyEvent,所以在这里只会返回关心ApplicationReadyEvent事件的listener。

SpringBoot ApplicationListener原理解析

缓存ApplicationListener

可以看到这个方法内部使用了缓存机制,先查询缓存中是否存在关注该ApplicationEventApplicationListener集合,有的话直接返回,否则再检索出相应的ApplicationListener,并放入到缓存中,下次再调用getApplicationListeners()时,则会直接返回缓存相关的listeners了。 SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

retrieveApplicationListeners()

根据事件检索出关注该事件的listener是在AbstractApplicationEventMulticasterretrieveApplicationListeners()方法实现的,有兴趣可以自行研究一下。

SpringBoot ApplicationListener原理解析

以下是获取当前注册的所有ApplicationListener,并根据ApplicationEvent事件类型筛选出仅关注该事件的listener相关代码

SpringBoot ApplicationListener原理解析

SpringBoot ApplicationListener原理解析

CachedListenerRetriever

筛选出来的ApplicationListener则是交由CachedListenerRetriever存放,从注释也可以看出该类的主要作用就是用来缓存特定的listener,有兴趣的话可以再自行研究该类源码。

SpringBoot ApplicationListener原理解析

总结

通过ApplicationListener实现事件监听,虽然涉及到了很多类,各种类之间的关联关系有点复杂,但是整体思路还是简单的,也是23种设计模式之一《观察者模式》的体现。

本质就是从Spring中获取所有ApplicationListener,并根据这些listener所关注的ApplicationEvent的不同,给listener做一个分类并缓存,在调用不同方法进行事件分发时,获取相关的listener集合,逐个遍历并调用其onApplicationEvent()方法。

结尾

转载自:https://juejin.cn/post/7265666141548150819
评论
请登录