启动流程

Spring Boot 的入口是 SpringApplication.run(),它完成环境准备、容器创建、Bean 加载、自动配置、嵌入式服务器启动等一系列工作。

整体流程

main()
  └── SpringApplication.run(Application.class, args)
        │
        ├─ 1. 创建 SpringApplication 实例
        │      确定应用类型(SERVLET / REACTIVE / NONE)
        │      加载 SpringApplicationRunListener(SPI)
        │
        ├─ 2. 发布 starting 事件
        │
        ├─ 3. 准备 Environment
        │      加载 application.yml / 环境变量 / 命令行参数
        │      发布 environmentPrepared 事件
        │
        ├─ 4. 打印 Banner
        │
        ├─ 5. 创建 ApplicationContext
        │      SERVLET → AnnotationConfigServletWebServerApplicationContext
        │
        ├─ 6. 准备 ApplicationContext
        │      注册 BeanDefinition(@SpringBootApplication 扫描)
        │      发布 contextPrepared 事件
        │
        ├─ 7. 刷新容器 refreshContext()
        │      加载所有 BeanDefinition
        │      执行自动配置(@EnableAutoConfiguration)
        │      实例化所有单例 Bean
        │      启动嵌入式 Web 服务器(Tomcat)
        │      发布 contextRefreshed 事件
        │
        ├─ 8. 发布 started 事件
        │
        ├─ 9. 执行 Runner
        │      ApplicationRunner.run()
        │      CommandLineRunner.run()
        │
        └─ 10. 发布 ready 事件(应用就绪)

关键阶段详解

阶段 3:Environment 准备

ConfigurableEnvironment 聚合了所有配置源(PropertySource),按优先级排列后统一查询。配置优先级详见 配置管理

// 监听 Environment 准备完成事件,可在此修改配置
@Component
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment env,
                                       SpringApplication app) {
        // 动态添加配置源(如从数据库、配置中心加载)
        Map<String, Object> props = new HashMap<>();
        props.put("custom.key", "value");
        env.getPropertySources().addFirst(
            new MapPropertySource("custom", props));
    }
}

需在 META-INF/spring.factories 中注册(Spring Boot 3.x 用 META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor)。

阶段 7:refreshContext

这是最重的阶段,调用 AbstractApplicationContext.refresh(),包含 12 个步骤:

refresh()
  ├── prepareRefresh()              初始化属性源
  ├── obtainFreshBeanFactory()      获取/创建 BeanFactory
  ├── prepareBeanFactory()          配置 BeanFactory(ClassLoader、后处理器等)
  ├── postProcessBeanFactory()      子类扩展点
  ├── invokeBeanFactoryPostProcessors()  执行 BeanFactoryPostProcessor
  │     包含 ConfigurationClassPostProcessor → 扫描 @Component、处理 @Import
  │     → 执行自动配置(AutoConfigurationImportSelector)
  ├── registerBeanPostProcessors()  注册 BeanPostProcessor
  ├── initMessageSource()           国际化
  ├── initApplicationEventMulticaster()
  ├── onRefresh()                   启动嵌入式 Web 服务器(Tomcat)
  ├── registerListeners()
  ├── finishBeanFactoryInitialization()  实例化所有非懒加载单例 Bean
  └── finishRefresh()               发布 ContextRefreshedEvent

自动配置加载机制详见 自动配置,Bean 实例化过程详见 Bean生命周期

阶段 9:Runner 回调

SpringApplication.run() 返回前,按 @Order 顺序执行所有 Runner:

// ApplicationRunner:参数封装为 ApplicationArguments
@Component
@Order(1)
public class DataInitRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (args.containsOption("init-data")) {
            dataService.initSeedData();
        }
        log.info("数据初始化完成");
    }
}
 
// CommandLineRunner:参数为原始字符串数组
@Component
@Order(2)
public class CacheWarmupRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        cacheService.warmup();
        log.info("缓存预热完成");
    }
}

Runner 在嵌入式服务器启动之后执行,此时应用已可接收请求,适合预热缓存、初始化数据、注册服务到注册中心等操作。


启动扩展点汇总

扩展点时机典型用途
EnvironmentPostProcessorEnvironment 准备后动态注入配置源
BeanDefinitionRegistryPostProcessorBeanDefinition 加载后,实例化前动态注册 Bean
BeanFactoryPostProcessor同上(更通用)修改 Bean 定义属性
BeanPostProcessor每个 Bean 初始化前后AOP 代理、属性注入
@PostConstructBean 依赖注入完成后单 Bean 的初始化逻辑
InitializingBean.afterPropertiesSet同上框架风格的初始化
ApplicationListener<ContextRefreshedEvent>容器刷新完成所有 Bean 就绪后的逻辑
ApplicationRunner / CommandLineRunner服务器启动后缓存预热、数据初始化
SmartLifecycle服务器启动后(可控顺序)启动/停止时的有序资源管理

Bean 初始化顺序

构造函数
  → 依赖注入(@Autowired / setter)
  → BeanPostProcessor.postProcessBeforeInitialization
  → @PostConstruct
  → InitializingBean.afterPropertiesSet
  → @Bean(initMethod = "init")
  → BeanPostProcessor.postProcessAfterInitialization

优雅停机

收到 SIGTERM
  → SmartLifecycle.stop()(按 phase 倒序)
  → DisposableBean.destroy()
  → @PreDestroy
  → DestroyMethod

优雅停机配置详见 优雅停机


启动事件监听

@Component
public class AppEventListener {
 
    // 容器刷新完成(所有 Bean 已就绪,服务器已启动)
    @EventListener(ApplicationReadyEvent.class)
    public void onReady(ApplicationReadyEvent event) {
        log.info("应用启动完毕,端口: {}",
            event.getApplicationContext()
                 .getEnvironment().getProperty("server.port"));
    }
 
    // 容器关闭前
    @EventListener(ContextClosedEvent.class)
    public void onClose() {
        log.info("应用正在关闭...");
    }
}

事件机制详见 事件机制


启动耗时分析

Spring Boot 2.5+ 内置了启动耗时分析,通过 Actuator 暴露:

management:
  endpoints:
    web:
      exposure:
        include: startup
# 获取各阶段启动耗时(需使用 BufferingApplicationStartup)
curl http://localhost:8080/actuator/startup
// Application 启动类中启用
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setApplicationStartup(new BufferingApplicationStartup(2048));
        app.run(args);
    }
}

减少启动时间的常见手段:

  • spring.main.lazy-initialization=true(延迟初始化,首次请求时再创建 Bean)
  • 减少 @ComponentScan 范围(精确指定 basePackages)
  • GraalVM 原生编译(AOT,启动降至毫秒级)详见 GraalVM原生编译

相关链接