SpringBoot 的启动流程是怎样的?
2026年02月04日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官抛出这个问题,绝不仅仅是希望你复述几个步骤。其核心考察点在于:
- 对 Spring Boot “约定大于配置” 理念的理解:你是否清楚 Spring Boot 如何简化了传统 Spring 应用的繁杂配置?这直接关联到自动配置 (
Auto-Configuration) 的核心机制。 - 对 Spring 框架 IOC 容器启动过程的掌握:Spring Boot 本质上是 Spring 框架的增强和封装。面试官想知道你是否了解其底层依然依赖
SpringApplication.run()和AbstractApplicationContext.refresh()这一核心生命周期。 - 对启动过程中关键扩展点的认知:你是否知道有哪些 “钩子”(如
ApplicationRunner,CommandLineRunner, 事件监听器ApplicationListener)可以在启动的不同阶段介入,并理解它们的执行时机? - 源码追踪和问题排查能力:能清晰描述启动流程的候选人,通常具备通过阅读启动日志和源码来分析和解决启动类失败、Bean 加载异常、配置不生效等实际问题的能力。
核心答案
Spring Boot 的启动流程可以概括为:初始化 Spring 应用实例,准备环境,创建并刷新 Spring IOC 容器,最终启动内嵌的 Web 服务器。
其核心入口是 SpringApplication.run(Class<?> primarySource, String... args) 静态方法。整个过程主要分为两大阶段:SpringApplication 实例的初始化和运行。
深度解析
让我们深入到关键步骤中,理解其原理和机制。
原理/机制
可以将整个流程分解为以下几个核心步骤:
1. 初始化阶段 (new SpringApplication(...))
- 推断应用类型:根据类路径下是否存在特定的类(如
Servlet,DispatcherHandler),判断应用是普通的Servlet应用(Spring MVC)、响应式Reactive Web应用,还是非 Web 应用。这决定了后续创建的ApplicationContext类型(如AnnotationConfigServletWebServerApplicationContext)。 - 加载
ApplicationContextInitializer:利用SpringFactoriesLoader机制,从META-INF/spring.factories文件中加载并实例化所有声明的初始化器。它们用于在ConfigurableApplicationContextrefresh()之前,对上下文进行自定义初始化。 - 加载
ApplicationListener:同样通过spring.factories加载应用事件监听器,用于监听在整个启动过程中发布的各种事件(如ApplicationStartedEvent,ApplicationReadyEvent)。
2. 运行阶段 (SpringApplication.run())
- 准备环境 (
prepareEnvironment):创建并配置应用环境 (ConfigurableEnvironment),这会加载所有的属性配置,包括application.properties/yml、命令行参数、系统属性等,并激活指定的profile。 - 创建并准备应用上下文 (
createApplicationContext):根据第一步推断的应用类型,实例化对应的ApplicationContext。然后,调用之前加载的所有ApplicationContextInitializer对其进行初始化,并将环境绑定到上下文。 - 刷新应用上下文 (
refreshContext- 最核心的一步):这是 Spring 框架容器启动的核心流程,由AbstractApplicationContext.refresh()方法定义。Spring Boot 在此基础上,通过refresh(ApplicationContext)方法进行了关键增强:- Bean 定义加载:通过
AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner扫描并注册所有 Bean(包括启动类上的@SpringBootApplication注解所涵盖的组件)。 - 自动配置 (
Auto-Configuration):这是 Spring Boot 的灵魂。@SpringBootApplication包含了@EnableAutoConfiguration,它会通过SpringFactoriesLoader加载META-INF/spring.factories中org.springframework.boot.autoconfigure.EnableAutoConfiguration键下指定的所有自动配置类。这些配置类根据条件(@ConditionalOnClass,@ConditionalOnMissingBean等)决定是否生效,从而自动创建并配置所需的 Bean(如DataSource,DispatcherServlet等)。 - 启动内嵌 Web 服务器:如果是 Web 应用,在
refresh过程的最后阶段,Spring Boot 会从容器中获取WebServerFactoryBean(如TomcatServletWebServerFactory),并调用其getWebServer()方法创建和启动内嵌的 Tomcat、Jetty 或 Undertow 服务器。
- Bean 定义加载:通过
- 执行 Runner (
callRunners):容器刷新完成后,会从容器中获取ApplicationRunner和CommandLineRunner接口的实现类,并执行它们的run方法。这两个接口常用于在应用完全启动后,执行一些初始化业务逻辑。
代码示例
一个高度简化的 SpringApplication.run() 核心逻辑示意:
// 这是一个概念性伪代码,用于说明流程
public class SpringApplication {
public ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
// 1. 初始化
this.primarySources = Collections.singleton(primarySource);
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 推断类型
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载Initializer
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // 加载Listener
// 2. 运行
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); // 准备环境
ConfigurableApplicationContext context = this.createApplicationContext(); // 创建上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 准备上下文
this.refreshContext(context); // <-- 核心:刷新上下文(执行自动配置,启动服务器)
this.callRunners(context, args); // 执行Runner
return context;
}
}
最佳实践与注意事项
- 自定义启动 Banner:在
resources下创建banner.txt可以自定义启动 Logo。 - 使用事件监听器:实现
ApplicationListener接口(或使用@EventListener注解)来在特定启动阶段执行代码,例如在ApplicationReadyEvent事件后执行数据库检查,这比在Runner中执行更安全(确保所有 Bean 已就绪)。 - 理解自动配置原理:当需要覆盖默认配置时,不是直接排除自动配置类,而是通过定义自己的
@Bean(利用@ConditionalOnMissingBean条件)或使用application.properties中的配置属性来定制。 - 注意 Runner 的执行顺序:可以通过
@Order注解来指定多个ApplicationRunner或CommandLineRunner的执行顺序。
常见误区
- 混淆 “自动配置” 和 “组件扫描”:
@SpringBootApplication包含了@ComponentScan,它负责扫描当前包及其子包下的@Component类。而自动配置是通过spring.factories从 classpath 的 jar 包中加载的,范围是全局的。 - 认为
main方法执行完应用才启动:实际上,SpringApplication.run()是一个阻塞方法,它会一直运行直到应用上下文被关闭(对于 Web 应用,就是内嵌服务器在运行)。 - 忽视启动失败分析:启动失败时,Spring Boot 会打印非常详细的
FailureAnalyzer报告。学会阅读这些报告是快速定位问题的关键。
总结
Spring Boot 的启动流程是一个精心设计的、事件驱动的过程,它通过 SpringApplication 类封装了传统 Spring 容器的初始化、refresh() 核心生命周期,并巧妙地利用 SpringFactoriesLoader 机制和条件注解实现了 “开箱即用” 的自动配置,最终通过内嵌 Web 服务器使得应用能够独立运行。理解这个过程,是掌握 Spring Boot 和高效排查启动问题的基石。