一、序言
本文简单分析一下 SpringBoot 的启动流程。
二、SpringBoot 启动源码分析
java
public ConfigurableApplicationContext run(String... args) {
// 记录当前时间的纳秒数,用于计算应用程序启动所花费的时间
long startTime = System.nanoTime();
// 创建一个默认的引导上下文对象
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 声明一个可配置的应用程序上下文对象,并初始化为 null
ConfigurableApplicationContext context = null;
// 配置 Headless 模式的属性
configureHeadlessProperty();
// 获取应用程序运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 通知监听器应用程序即将启动
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 创建应用程序参数对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境,包括配置文件加载、属性设置等
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置环境,忽略 Bean 信息
configureIgnoreBeanInfo(environment);
// 打印启动横幅
Banner printedBanner = printBanner(environment);
// 创建应用程序上下文对象
context = createApplicationContext();
// 设置应用程序启动对象
context.setApplicationStartup(this.applicationStartup);
// 准备上下文,包括设置环境、监听器、应用程序参数等
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新应用程序上下文
refreshContext(context);
// 刷新后的操作,如注册关闭钩子等
afterRefresh(context, applicationArguments);
// 计算应用程序启动所花费的时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
// 如果需要记录启动信息,则记录应用程序启动完成的日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 通知监听器应用程序已经启动
listeners.started(context, timeTakenToStartup);
// 执行应用程序中的所有 ApplicationRunner 和 CommandLineRunner 实例
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;
}
三、SpringBoot 启动流程分析
我们可以将 SpringBoot 启动流程归纳为上面的几个大阶段:
- 初始化和准备阶段:这个阶段包括记录启动时间、创建引导上下文、配置 Headless 属性、获取运行监听器、环境准备以及打印 Banner 等步骤。这个阶段的主要目标是为接下来的步骤做好准备。
- 创建应用程序上下文阶段:这个阶段主要是创建 ApplicationContext 实例,并加载 Bean 定义。这个阶段的主要目标是创建并初始化 Spring 的 IoC 容器。
- 刷新应用程序上下文阶段:这个阶段主要是完成 Bean 的初始化,包括调用初始化方法、完成 Bean 的依赖注入等,以及调用所有的 ApplicationRunner 和 CommandLineRunner 的 run 方法。这个阶段的主要目标是完成应用程序的启动。
- 就绪阶段:这个阶段的主要目标是确保应用程序已经准备就绪,可以开始接受和处理请求了。