SpringBoot中文注释项目Github地址:
https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE
本篇接 SpringApplication对象是如何构建的? SpringBoot源码(八)
1 温故而知新
温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了SpringApplication对象的构建过程及SpringBoot自己实现的一套SPI机制,现将关键步骤再浓缩总结下:
SpringApplication
对象的构造过程其实就是给SpringApplication
类的6个成员变量赋值;- SpringBoot通过以下步骤实现自己的SPI机制:
- 1)首先获取线程上下文类加载器;
- 2)然后利用上下文类加载器从
spring.factories
配置文件中加载所有的SPI扩展实现类并放入缓存中; - 3)根据SPI接口从缓存中取出相应的SPI扩展实现类;
- 4)实例化从缓存中取出的SPI扩展实现类并返回。
2 引言
在SpringBoot启动过程中,每个不同的启动阶段会分别广播不同的内置生命周期事件,然后相应的监听器会监听这些事件来执行一些初始化逻辑工作比如ConfigFileApplicationListener
会监听onApplicationEnvironmentPreparedEvent
事件来加载配置文件application.properties
的环境变量等。
因此本篇内容将来分析下SpringBoot的事件监听机制的源码。
3 SpringBoot广播内置生命周期事件流程分析
为了探究SpringBoot广播内置生命周期事件流程,我们再来回顾一下SpringBoot的启动流程代码:
// SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 【0】新建一个SpringApplicationRunListeners对象用于发射SpringBoot启动过程中的生命周期事件
SpringApplicationRunListeners listeners = getRunListeners(args);
// 【1】》》》》》发射【ApplicationStartingEvent】事件,标志SpringApplication开始启动
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 【2】》》》》》发射【ApplicationEnvironmentPreparedEvent】事件,此时会去加载application.properties等配置文件的环境变量,同时也有标志环境变量已经准备好的意思
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] {
ConfigurableApplicationContext.class }, context);
// 【3】》》》》》发射【ApplicationContextInitializedEvent】事件,标志context容器被创建且已准备好
// 【4】》》》》》发射【ApplicationPreparedEvent】事件,标志Context容器已经准备完成
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 【5】》》》》》发射【ApplicationStartedEvent】事件,标志spring容器已经刷新,此时所有的bean实例都已经加载完毕
listeners.started(context);
callRunners(context, applicationArguments);
}
// 【6】》》》》》发射【ApplicationFailedEvent】事件,标志SpringBoot启动失败
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 【7】》》》》》发射【ApplicationReadyEvent】事件,标志SpringApplication已经正在运行即已经成功启动,可以接收服务请求了。
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);