Spring Boot 启动流程
Spring Boot 启动流程包含多个阶段,每个阶段执行特定职责,共同完成应用初始化。
启动入口
SpringApplication.run()
Java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
SpringApplicationRunListeners listeners = getRunListeners(args);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Banner banner = printBanner(environment);
context = createApplicationContext();
context.setEnvironment(environment);
prepareContext(bootstrapContext, context, listeners, applicationArguments, banner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
listeners.started(context, stopWatch);
callRunners(context, applicationArguments);
listeners.ready(context, stopWatch);
} catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw ex;
}
return context;
}
启动阶段详解
阶段1:启动准备
Java
// 1. 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 2. 获取运行监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 3. 广播启动事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
阶段2:环境准备
Java
// 1. 创建应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 2. 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(...) {
// 创建 Environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置属性源
configureEnvironment(environment, args);
// 附加配置属性源
ConfigurationPropertySources.attach(environment);
// 广播环境准备事件
listeners.environmentPrepared(bootstrapContext, environment);
return environment;
}
阶段3:创建上下文
Java
// 1. 打印 Banner
Banner banner = printBanner(environment);
// 2. 创建 ApplicationContext
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
switch (this.webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
}
阶段4:准备上下文
Java
prepareContext(bootstrapContext, context, listeners, applicationArguments, banner);
private void prepareContext(...) {
// 设置环境
context.setEnvironment(environment);
// 后处理上下文
postProcessApplicationContext(context);
// 执行 ApplicationContextInitializer
applyInitializers(context);
// 广播上下文准备事件
listeners.contextPrepared(context);
// 注册主配置类
load(context, sources);
// 广播上下文加载事件
listeners.contextLoaded(context);
}
阶段5:刷新上下文
Java
refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
// 执行 refresh()
context.refresh();
// 注册关闭钩子
if (this.registerShutdownHook) {
context.registerShutdownHook();
}
}
阶段6:启动完成
Java
// 1. 后刷新处理
afterRefresh(context, applicationArguments);
// 2. 广播启动完成事件
listeners.started(context, stopWatch);
// 3. 执行 Runner
callRunners(context, applicationArguments);
// 4. 广播就绪事件
listeners.ready(context, stopWatch);
启动事件序列
| 事件 | 触发时机 | 主要作用 |
|---|---|---|
| ApplicationStartingEvent | 启动开始 | 初始化早期组件 |
| ApplicationEnvironmentPreparedEvent | 环境准备完成 | 加载配置文件 |
| ApplicationContextInitializedEvent | 上下文初始化 | 执行 Initializer |
| ApplicationPreparedEvent | 上下文准备完成 | BeanDefinition 注册 |
| ApplicationStartedEvent | 上下文刷新完成 | 容器启动 |
| ApplicationReadyEvent | Runners 执行完成 | 应用就绪 |
WebApplicationType 判断
类型判断逻辑
Java
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null)
&& !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
return WebApplicationType.REACTIVE;
}
if (ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
return WebApplicationType.SERVLET;
}
return WebApplicationType.NONE;
}
类型说明
| 类型 | 特征 | ApplicationContext |
|---|---|---|
| SERVLET | 存在 DispatcherServlet | ServletWebServerApplicationContext |
| REACTIVE | 存在 Reactive Handler | ReactiveWebServerApplicationContext |
| NONE | 非 Web 应用 | AnnotationConfigApplicationContext |
Runner 执行
ApplicationRunner
Java
@Component
@Order(1)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 启动后执行逻辑
System.out.println("ApplicationRunner executed");
}
}
CommandLineRunner
Java
@Component
@Order(2)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 启动后执行逻辑
System.out.println("CommandLineRunner executed");
}
}
Runner 执行顺序
Java
private void callRunners(ApplicationContext context, ApplicationArguments args) {
// 合并所有 Runner
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 按 Order 排序
AnnotationAwareOrderComparator.sort(runners);
// 依次执行
for (Object runner : runners) {
if (runner instanceof ApplicationRunner) {
((ApplicationRunner) runner).run(args);
}
if (runner instanceof CommandLineRunner) {
((CommandLineRunner) runner).run(args.getSourceArgs());
}
}
}
启动失败处理
异常处理流程
Java
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
SpringApplicationRunListeners listeners) {
// 1. 广播失败事件
listeners.failed(context, exception);
// 2. 发布失败事件
if (context != null) {
context.publishEvent(new ApplicationFailedEvent(this, args, context, exception));
}
// 3. 关闭上下文
if (context != null) {
context.close();
}
}
注意:理解启动流程对排查启动问题和优化启动时间至关重要。
要点总结
- 启动流程包含 6 个主要阶段
- 每个阶段广播对应事件通知监听器
- refresh() 是核心阶段,完成 Bean 初始化
- Runner 在容器启动后执行,用于初始化任务
- WebApplicationType 决定容器类型选择
📝 发现内容有误?点击此处直接编辑