全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-18 10 分钟 ✍️ juanwangdev

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上下文刷新完成容器启动
ApplicationReadyEventRunners 执行完成应用就绪

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存在 DispatcherServletServletWebServerApplicationContext
REACTIVE存在 Reactive HandlerReactiveWebServerApplicationContext
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 决定容器类型选择

📝 发现内容有误?点击此处直接编辑

← 上一篇 SpringApplication 初始化
下一篇 → 内嵌 Web 容器启动
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库