Spring Boot 启动流程

候选人小汤在面试美团 P6 时,面试官问道:

"Spring Boot 应用是怎么启动的?"

小汤说:"调用 SpringApplication.run()..."

面试官追问:"run() 方法里面做了什么?"

小汤说:"会创建 ApplicationContext..."

面试官:"那 prepareContext 和 refreshContext 分别是做什么的?"

小汤答不上来。

【面试官心理】 这道题我用来测试候选人对 Spring Boot 启动流程的理解深度。知道 SpringApplication.run() 只是第一步,能说出 refreshContext 中做了什么的,才是真正理解 Spring Boot 的人。


一、核心问题 🔴

1.1 问题拆解

第一层:入口

  • "SpringApplication.run() 的完整流程是什么?"
  • "new SpringApplication() 做了什么?"

第二层:启动步骤

  • "prepareContext 和 refreshContext 有什么区别?"
  • "afterRefresh 是什么时候调用的?"

第三层:扩展点

  • "SpringApplicationBuilder 怎么用?"
  • "ApplicationContextInitializer 是什么时候调用的?"

1.2 标准回答

P5 回答:主要阶段

Spring Boot 启动流程:

SpringApplication.run()
  ├─ 1. 创建 SpringApplication 对象
  │     ├─ 推断应用类型(Servlet、Reactive、None)
  │     ├─ 加载 spring.factories 中的 BootstrapRegistryInitializer
  │     └─ 设置初始化器(ApplicationContextInitializer)
  │     └─ 设置监听器(ApplicationListener)
  │     └─ 推断主类

  ├─ 2. 运行 run()
  │     ├─ 获取并启动监听器
  │     ├─ 准备环境(Environment)
  │     ├─ 创建 ApplicationContext
  │     ├─ 准备上下文(prepareContext)
  │     ├─ 刷新上下文(refreshContext)
  │     ├─ 刷新后处理(afterRefresh)
  │     └─ 返回 ApplicationContext

1.3 追问升级

追问 1:refreshContext 详解

// SpringApplication.refreshContext()
public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
}

// 核心流程
public ConfigurableApplicationContext run(String... args) {
    // ... 前置步骤 ...

    // 刷新上下文
    refreshContext(context);

    // 刷新后处理
    afterRefresh(context, arguments);

    return context;
}

private void refreshContext(ConfigurableApplicationContext context) {
    // 委托给 Spring 的 AbstractApplicationContext.refresh()
    // 这就是 Spring 容器的初始化过程
    // 1. prepareBeanFactory
    // 2. postProcessBeanFactory
    // 3. invokeBeanFactoryPostProcessors
    // 4. registerBeanPostProcessors
    // 5. initMessageSource
    // 6. initApplicationEventMulticaster
    // 7. onRefresh
    // 8. registerListeners
    // 9. finishBeanFactoryInitialization
    // 10. finishRefresh
}

追问 2:扩展点

// ApplicationContextInitializer - 在容器刷新之前调用
public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 可以修改容器配置
    }
}

// SpringApplicationBuilder 配置
new SpringApplicationBuilder()
    .sources(MyApplication.class)
    .initializers(new MyInitializer())
    .listeners(new MyListener())
    .run(args);

二、面试总结

Spring Boot 启动流程的核心是 SpringApplication.run() + AbstractApplicationContext.refresh()。