spring boot启动流程 简单理解版

Spring Boot 的启动流程是其核心机制之一,理解它对于排查启动问题、进行性能优化以及开发自定义 Starter 都至关重要。

在我看来,Spring Boot 的启动流程本质上是 “Spring 容器初始化” 与 “自动化配置” 的结合。我们可以将其清晰地划分为三个主要阶段:准备阶段、核心初始化阶段 和 收尾阶段。

下面我将结合源码逻辑,为您详细拆解这个过程。

🚀 第一阶段:启动准备(SpringApplication 实例化)

当我们调用 SpringApplication.run(Application.class, args) 时,流程开始。

1.  推断应用类型:Spring Boot 会通过 ClassUtils 扫描类路径(classpath),判断当前应用类型。
   *   如果存在 Servlet 和 ConfigurableWebApplicationContext,则为 SERVLET 环境(传统 Web)。
   *   如果存在 Reactive 相关类,则为 REACTIVE 环境。
   *   否则为非 Web 环境(NONE)。
2.  加载初始化器和监听器:通过 SpringFactoriesLoader 机制,加载 META-INF/spring.factories 文件中配置的 ApplicationContextInitializer 和 ApplicationListener。这是 Spring Boot SPI 机制的典型应用。
3.  推断主类:通过栈追踪找到包含 main 方法的类,作为后续的核心配置类。

⚙️ 第二阶段:核心运行流程(run() 方法执行)

这是最复杂的阶段,包含了环境准备、容器创建和核心刷新逻辑。

1. 环境准备(Environment)
*   创建环境对象:根据第一步推断的类型,创建对应的 Environment(如 StandardServletEnvironment)。
*   配置加载与合并:按优先级加载配置源(命令行参数 > 系统变量 > 配置文件 application.yml/properties 等)。
*   激活 Profiles:根据配置激活对应的环境(如 dev, prod)。
*   事件发布:发布 ApplicationEnvironmentPreparedEvent,通知监听器环境已准备就绪。

2. 创建应用上下文(ApplicationContext)
根据应用类型,通过反射创建具体的容器实现:
*   Web 应用:AnnotationConfigServletWebServerApplicationContext
*   非 Web 应用:AnnotationConfigApplicationContext

3. 上下文预处理
*   初始化器执行:调用之前加载的 ApplicationContextInitializer 的 initialize() 方法,对上下文进行进一步设置(如设置环境、资源加载器等)。
*   主类注册:将我们的启动类(Application.class)注册为容器中的一个 Bean 定义,以确保后续的组件扫描和配置生效。

4. 核心刷新(refreshContext)—— 最关键的一步
这是 Spring 框架的核心,也是自动配置和 Web 服务器启动的触发点。主要包含以下子步骤:

*   BeanFactory 初始化:创建 DefaultListableBeanFactory,这是 Bean 管理的引擎。
*   执行 BeanFactoryPostProcessor:
   *   ConfigurationClassPostProcessor 解析 @ComponentScan,扫描所有组件并注册 Bean 定义。
   *   解析 @EnableAutoConfiguration:这是自动配置的核心。它通过 SpringFactoriesLoader 加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(Spring Boot 2.7+ 主要使用此文件,旧版本使用 spring.factories)中的自动配置类。
   *   条件装配:利用 @ConditionalOnClass、@ConditionalOnMissingBean 等注解,根据类路径和容器状态,决定是否将这些自动配置类生效。
*   注册 BeanPostProcessor:注册 Bean 后置处理器,用于 AOP 代理等增强操作。
*   实例化非懒加载单例:实例化所有非懒加载的单例 Bean(调用构造方法、执行 @PostConstruct、进行依赖注入)。
*   嵌入式 Web 服务器启动:如果是 Web 应用,在 onRefresh() 阶段会创建并启动内嵌的 Tomcat/Jetty/Undertow 服务器,绑定端口并启动线程池。

🏁 第三阶段:启动收尾(Running)

1.  执行 Runners:调用容器中所有的 CommandLineRunner 和 ApplicationRunner 的 run() 方法。这通常用于在应用启动后执行一些特定的逻辑(如数据预热、缓存加载)。它们支持 @Order 注解来控制执行顺序。
2.  发布就绪事件:发布 ApplicationReadyEvent。这标志着 Spring Boot 应用已经完全启动,可以接收外部请求了。这也是我们实现“优雅上线”的关键点——只有发布此事件后,注册中心(如 Nacos)才会将流量打过来。
3.  计时结束:打印启动耗时日志。

📊 总结与关键点提炼

为了方便记忆和理解,我整理了一个简化的流程表:
阶段   核心动作   关键技术/类
1. 实例化   推断类型、加载扩展点   SpringApplication 构造函数、SpringFactoriesLoader
2. 运行   准备环境、创建容器   Environment、ApplicationContext
3. 刷新   组件扫描、自动配置、启动服务器   @ComponentScan、@EnableAutoConfiguration、refresh()
4. 收尾   执行 Runner、发布就绪事件   CommandLineRunner、ApplicationRunner、ApplicationReadyEvent

💡 高级视角的补充(加分项)

1.  自动配置的演进:在 Spring Boot 2.7 之前,自动配置类主要定义在 META-INF/spring.factories 的 EnableAutoConfiguration 配置项下。从 2.7 开始,官方推荐将它们迁移到 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中,以提高启动性能。作为资深开发,我在编写自定义 Starter 时会遵循最新的规范。
2.  条件化配置:自动配置并不是“一拥而上”,而是基于 @Conditional 系列注解(如 @ConditionalOnClass、@ConditionalOnWebApplication)进行精确的按需加载。这保证了即使引入了大量 Starter,只要环境不满足,就不会产生额外的 Bean,从而保证了轻量级。
3.  事件监听机制:整个启动流程是一个典型的事件驱动模型。我们可以实现 ApplicationListener 监听特定事件(如 ApplicationStartingEvent、ApplicationPreparedEvent),在不同时期介入容器的生命周期,实现定制化逻辑。

这就是我对 Spring Boot 启动流程的理解。它通过约定优于配置的理念,将繁琐的容器初始化、组件扫描和配置加载过程自动化,极大地简化了开发者的体验。