SpringBoot启动流程分析2–run方法
一、概述
源码基于SpringBoot 2.7.xx版本
1.1 简介
SpringBoot启动流程大致分为两个阶段,第一个阶段是SpringApplication 实例化,第二个阶段为执行 run
方法,本章讲解第二阶段,第二阶段内容较多,接下来分篇讲解
- 初始化引导上下文–bootStrapContext
- 创建应用上下文环境–ConfigurableEnvironment
- 创建应用上下文–createApplicationContext
- 准备应用上下文–prepareContext
- 刷新应用上下文–refreshContext
- 刷新应用上下文后的扩展接口–afterRefresh(空方法)
- 调用ApplicationRunner和CommandLineRunner对应的run方法
SpringApplication的启动流程各时期发出的Event事件:
- ApplicationStartingEvent(1.初始化引导上下文后,发布应用启动事件)
- ApplicationEnvironmentPreparedEvent(2.创建应用上下文环境时,发布应用环境已准备完毕事件)
- ApplicationContextInitializedEvent(4.准备应用上下文时,发布应用上下文已初始化事件)
- ApplicationPreparedEvent(4.准备应用上下文时,发布应用上下文已准备完毕事件)
- ApplicationStartedEvent(6.刷新应用上下文后的扩展接口后,发布应用上下文已启动事件)
- ApplicationReadyEvent(7.调用ApplicationRunner和CommandLineRunner对应的run方法后,发布应用上下文准备就绪事件)
- ApplicationFailedEvent(如果2-7步中出现异常,则发布应用上下文启动失败事件)
1.2 名词解释
- 应用上下文–ApplicationContext
可以理解成IoC容器的高级表现形式,应用上下文确实是在IoC容器的基础上丰富了一些高级功能。 - IoC容器–DefaultListableBeanFactory
应用上下文有一个属性beanFactory,就是IoC容器–DefaultListableBeanFactory,他们之间是持有和扩展的关系。
二、详解
2.1 SpringApplication的run方法
public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
// 开启时间监控
long startTime = System.nanoTime();
// 1. 初始化引导上下文--bootStrapContext
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 这个是设置系统参数:java.awt.headless
configureHeadlessProperty();
// 获取监听器--SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发 ApplicationStartingEvent事件,LoggingApplicationListener 监听器进行监听
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 2. 创建应用上下文环境--ConfigurableEnvironment
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
// 这里就是打印图标的地方,默认是会打印Spring,如果你设置了其他图标,那么就打印设置的图标
Banner printedBanner = printBanner(environment);
// 3. 创建应用上下文--ConfigurableApplicationContext
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 4. 准备应用上下文--prepareContext
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 5. 刷新应用上下文--refreshContext
refreshContext(context);
// 6. 刷新应用上下文后的扩展接口--afterRefresh(空方法)
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
// 7. 调用ApplicationRunner和CommandLineRunner对应的run方法
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
} catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
}
2.2 初始化引导上下文–bootStrapContext
public class SpringApplication {
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
}
2.3 初始化运行监听器–SpringApplicationRunListener
SpringApplicationRunListener用来在整个启动流程中接收不同执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的
启动流程,在各个启动流程广播相应的事件。
public class SpringApplication {
/**
* 获取所有运行监听器
* @param args
* @return
*/
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
// 实例化classpath下 META-INF/spring.factories中已配置的 SpringApplicationRunListener
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
}
SpringApplicationRunListener:
public interface SpringApplicationRunListener {
// 初始化引导上下文后,发布应用启动事件
default void starting(ConfigurableBootstrapContext bootstrapContext) {
}
// 创建应用上下文环境时,发布应用环境已准备完毕事件
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
}
// 准备应用上下文时,发布应用上下文已初始化事件
default void contextPrepared(ConfigurableApplicationContext context) {
}
// 准备应用上下文时,发布应用上下文已准备完毕事件
default void contextLoaded(ConfigurableApplicationContext context) {
}
// 刷新应用上下文后的扩展接口后,发布应用上下文已启动事件
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
started(context);
}
// 调用ApplicationRunner和CommandLineRunner对应的run方法后,发布应用上下文准备就绪事件
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
running(context);
}
// 如果2-7步中出现异常,则发布应用上下文启动失败事件
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
SpringApplicationRunListeners、SpringApplicationRunListener和ApplicationListener的关系:
- SpringApplicationRunListener接口规定了SpringBoot的启动流程/生命周期
- SpringApplicationRunListeners是SpringApplicationRunListener的封装,SpringApplicationRunListeners中包含
多个SpringApplicationRunListener,是为了批量执行的封装。- SpringApplicationRunListeners与SpringApplicationRunListener方法相同,
调用每个启动流程的SpringApplicationRunListener方法,然后广播相应的事件到Spring框架的ApplicationListener。