1 引言
在SpringBoot启动过程中,每个不同的启动阶段会分别广播不同的内置生命周期事件,然后相应的监听器会监听这些事件来执行一些初始化逻辑工作比如ConfigFileApplicationListener会监听onApplicationEnvironmentPreparedEvent事件来加载配置文件application.properties的环境变量等。
因此本篇内容将来分析下SpringBoot的事件监听机制的源码。
2 SpringBoot广播内置生命周期事件流程分析
为了探究SpringBoot广播内置生命周期事件流程,我们再来回顾一下SpringBoot的启动流程代码:
1 | // SpringApplication.java |
可以看到SpringBoot在启动过程中首先会先新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的各种生命周期事件,比如发射ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent和ApplicationContextInitializedEvent等事件,然后相应的监听器会执行一些SpringBoot启动过程中的初始化逻辑。那么,监听这些SpringBoot的生命周期事件的监听器们是何时被加载实例化的呢?还记得上篇文章在分析SpringApplication的构建过程吗?没错,这些执行初始化逻辑的监听器们正是在SpringApplication的构建过程中根据ApplicationListener接口去spring.factories配置文件中加载并实例化的。
2.1 为广播SpringBoot内置生命周期事件做前期准备
2.1.1 加载ApplicationListener监听器实现类
我们再来回顾下SpringApplication对象是如何构建的? SpringBoot源码(八)一文中讲到在构建SpringApplication对象时的setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));这句代码。
这句代码做的事情就是从spring.factories中加载出ApplicationListener事件监听接口的SPI扩展实现类然后添加到SpringApplication对象的listeners集合中,用于后续监听SpringBoot启动过程中的事件,来执行一些初始化逻辑工作。
SpringBoot启动时的具体监听器们都实现了ApplicationListener接口,其在spring.factories部分配置如下:

不过在调试时,会从所有的spring.factories配置文件中加载监听器,最终加载了10个监听器。如下图:

2.1.2 加载SPI扩展类EventPublishingRunListener
前面讲到,在SpringBoot的启动过程中首先会先新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的生命周期事件,即我们现在来看下SpringApplicationRunListeners listeners = getRunListeners(args);这句代码:
1 | // SpringApplication.java |
我们将重点放到getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)这句代码,getSpringFactoriesInstances这个方法我们已经很熟悉,在上一篇分析SpringBoot的SPI机制时已经详细分析过这个方法。可以看到SpringBoot此时又是根据SpringApplicationRunListener这个SPI接口去spring.factories中加载相应的SPI扩展实现类,我们直接去spring.factories中看看SpringApplicationRunListener有哪些SPI实现类:

由上图可以看到,SpringApplicationRunListener只有EventPublishingRunListener这个SPI实现类 EventPublishingRunListener这个哥们在SpringBoot的启动过程中尤其重要,由其在SpringBoot启动过程的不同阶段发射不同的SpringBoot的生命周期事件,即SpringApplicationRunListeners对象没有承担广播事件的职责,而最终是委托EventPublishingRunListener这个哥们来广播事件的。
因为从spring.factories中加载EventPublishingRunListener类后还会实例化该类,那么我们再跟进EventPublishingRunListener的源码,看看其是如何承担发射SpringBoot生命周期事件这一职责的?
1 | // EventPublishingRunListener.java |
可以看到EventPublishingRunListener类实现了SpringApplicationRunListener接口,SpringApplicationRunListener接口定义了SpringBoot启动时发射生命周期事件的接口方法,而EventPublishingRunListener类正是通过实现SpringApplicationRunListener接口的starting,environmentPrepared和contextPrepared等方法来广播SpringBoot不同的生命周期事件,我们直接看下SpringApplicationRunListener接口源码好了:
1 | // SpringApplicationRunListener.java |
我们再接着分析EventPublishingRunListener这个类,可以看到其有一个重要的成员属性initialMulticaster,该成员属性是SimpleApplicationEventMulticaster类对象,该类正是承担了广播SpringBoot启动时生命周期事件的职责,即EventPublishingRunListener对象没有承担广播事件的职责,而最终是委托SimpleApplicationEventMulticaster这个哥们来广播事件的。 从EventPublishingRunListener的源码中也可以看到在starting,environmentPrepared和contextPrepared等方法中也正是通过调用SimpleApplicationEventMulticaster类对象的multicastEvent方法来广播事件的。
思考 SpringBoot启动过程中发射事件时事件广播者是层层委托职责的,起初由
SpringApplicationRunListeners对象承担,然后SpringApplicationRunListeners对象将广播事件职责委托给EventPublishingRunListener对象,最终EventPublishingRunListener对象将广播事件的职责委托给SimpleApplicationEventMulticaster对象。为什么要层层委托这么做呢? 这个值得大家思考。
前面讲到从spring.factories中加载出EventPublishingRunListener类后会实例化,而实例化必然会通过EventPublishingRunListener的构造函数来进行实例化,因此我们接下来分析下EventPublishingRunListener的构造函数源码:
1 | // EventPublishingRunListener.java |
可以看到在EventPublishingRunListener的构造函数中有一个for循环会遍历之前从spring.factories中加载的监听器们,然后添加到集合中缓存起来,用于以后广播各种事件时直接从这个集合中取出来即可,而不用再去spring.factories中加载,提高效率。
2.2 广播SpringBoot的内置生命周期事件
从spring.factories配置文件中加载并实例化EventPublishingRunListener对象后,那么在在SpringBoot的启动过程中会发射一系列SpringBoot内置的生命周期事件,我们再来回顾下SpringBoot启动过程中的源码:
1 | // SpringApplication.java |
可以看到在SpringBoot的启动过程中总共会发射7种不同类型的生命周期事件,来标志SpringBoot的不同启动阶段,同时,这些生命周期事件的监听器们也会执行一些启动过程中的初始化逻辑,关于这些监听器的初始化逻辑将在下一篇内容中会分析。以下是SpringBoot启动过程中要发射的事件类型,其中ApplicationFailedEvent在SpringBoot启动过程中遇到异常才会发射:
ApplicationStartingEventApplicationEnvironmentPreparedEventApplicationContextInitializedEventApplicationPreparedEventApplicationStartedEventApplicationFailedEventApplicationReadyEvent
我们以listeners.starting();这句代码为例,看看EventPublishingRunListener对象发射事件的源码:
1 | // SpringApplicationRunListeners.java |
继续跟进listener.starting();的源码:
1 | EventPublishingRunListener.java |
可以看到,EventPublishingRunListener对象将发布ApplicationStartingEvent这件事情委托给了SimpleApplicationEventMulticaster对象initialMulticaster, ,而initialMulticaster对象最终会调用其multicastEvent方法来发射ApplicationStartingEvent事件。关于SimpleApplicationEventMulticaster类如何广播事件,笔者已经在Spring是如何实现事件监听机制的? Spring源码(二)这篇文章已经详细分析,这里不再赘述。
关于SpringBoot启动过程中发射其他生命周期事件的源码这里不再分析
3 SpringBoot的内置生命周期事件总结
好了,前面已经分析了SpringBoot启动过程中要发射的各种生命周期事件,下面列一个表格总结下:

4 小结
SpringBoot启动过程中广播生命周期事件的源码分析就到此结束了,下一篇会继续介绍监听这些生命周期事件的监听器们。我们再回顾本篇内容总结下关键点:
SpringBoot启动过程中会发射7种类型的生命周期事件,标志不同的启动阶段,然后相应的监听器会监听这些事件来执行一些初始化逻辑工作。