乐于分享
好东西不私藏

Spring Boot 源码解析(一):从零开始读懂 Spring Boot 启动流程

Spring Boot 源码解析(一):从零开始读懂 Spring Boot 启动流程

大家好,我是老 J。

微服务系列完结后,很多朋友问:“老 J,Spring Boot 源码能讲讲吗?面试总被问。”

安排。

这个系列不贴大段源码,而是用流程图 + 核心逻辑 + 面试回答的方式,帮你真正理解 Spring Boot 的底层原理。

第一期,从最经典的面试题开始:Spring Boot 启动流程是怎样的?

一、一个最简单的 Spring Boot 应用

@SpringBootApplicationpublicclassApplication {publicstaticvoidmain(String[] args) {        SpringApplication.run(Application.class, args);    }}

就这么几行代码,启动了:

  • • Tomcat(或 Jetty/Undertow)
  • • Spring IOC 容器
  • • 自动配置(数据源、MVC、Redis…)
  • • 所有 Bean 的实例化

问题:这一行 SpringApplication.run() 背后到底发生了什么?

二、启动流程全景图(面试必背)

┌─────────────────────────────────────────────────────────────────┐│                     SpringApplication.run()                      │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  1. 启动监听器:SpringApplicationRunListeners 开始通知          │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  2. 推断应用类型:是 Servlet(Web)还是 Reactive(响应式)       │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  3. 加载 Spring 工厂:从 META-INF/spring.factories 加载配置     │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  4. 寻找并实例化初始化器:ApplicationContextInitializer         │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  5. 创建并准备 Environment:加载配置文件(application.yml)     │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  6. 打印 Banner:Spring Boot 启动时的那个大图标                 │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  7. 创建 IOC 容器:根据应用类型创建(AnnotationConfig...)      │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  8. 准备容器:将 Environment 等设置到容器                       │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  9. 刷新容器:refresh()——最核心!做 Bean 解析、注册、实例化    │└─────────────────────────────────┬───────────────────────────────┘                                  │                                  ▼┌─────────────────────────────────────────────────────────────────┐│  10. 启动完成,执行 Runner:CommandLineRunner / ApplicationRunner│└─────────────────────────────────────────────────────────────────┘

三、逐层拆解:每一步在干什么?

第1步:推断应用类型

// SpringApplication 构造函数中this.webApplicationType = WebApplicationType.deduceFromClasspath();

推断逻辑:

  • • 有 org.springframework.web.reactive.DispatcherHandler → REACTIVE
  • • 有 javax.servlet.Servlet 或 org.springframework.web.context.ConfigurableWebApplicationContext → SERVLET
  • • 都没有 → NONE

面试回答: “Spring Boot 会根据 classpath 中是否存在特定类自动判断是 Servlet 容器(Tomcat)、响应式容器(Netty)还是普通应用。”

第2步:加载 Spring 工厂

从 META-INF/spring.factories 中加载各种配置:

# spring-boot-autoconfigure/META-INF/spring.factories(部分)org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\...

这就是自动配置的源头。

第3步:创建 Environment

读取:

  • • application.properties
  • • application.yml
  • • 命令行参数
  • • 系统环境变量

优先级: 命令行 > 环境变量 > 配置文件

第4步:创建 IOC 容器

// 根据应用类型创建不同的容器if (webApplicationType == SERVLET) {    context = newAnnotationConfigServletWebServerApplicationContext();elseif (webApplicationType == REACTIVE) {    context = newAnnotationConfigReactiveWebServerApplicationContext();else {    context = newAnnotationConfigApplicationContext();}

第5步:刷新容器——最核心!

// AbstractApplicationContext.refresh()@Overridepublicvoidrefresh()throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1. 刷新前的准备工作        prepareRefresh();// 2. 获取 BeanFactoryConfigurableListableBeanFactorybeanFactory= obtainFreshBeanFactory();// 3. BeanFactory 的准备工作(设置类加载器、后置处理器等)        prepareBeanFactory(beanFactory);// 4. 子类处理(Web 容器会在这里启动 Tomcat)        postProcessBeanFactory(beanFactory);// 5. 调用 BeanFactory 后置处理器        invokeBeanFactoryPostProcessors(beanFactory);// 6. 注册 Bean 后置处理器        registerBeanPostProcessors(beanFactory);// 7. 初始化消息源(国际化)        initMessageSource();// 8. 初始化事件广播器        initApplicationEventMulticaster();// 9. 子类初始化(Web 容器在这里完成启动)        onRefresh();// 10. 注册监听器        registerListeners();// 11. 实例化所有非懒加载的单例 Bean        finishBeanFactoryInitialization(beanFactory);// 12. 完成刷新,发布 ContextRefreshedEvent        finishRefresh();    }}

四、Tomcat 是怎么启动的?

Web 容器的启动发生在 onRefresh() 方法中。

// ServletWebServerApplicationContext.onRefresh()@OverrideprotectedvoidonRefresh() {super.onRefresh();try {        createWebServer();  // 创建 Tomcat    } catch (Throwable ex) {thrownewApplicationContextException("Unable to start web server", ex);    }}privatevoidcreateWebServer() {// 获取 WebServerFactory(TomcatServletWebServerFactory)WebServerFactoryfactory= getWebServerFactory();// 创建 Tomcat WebServerthis.webServer = factory.getWebServer(getSelfInitializer());}

五、面试怎么回答?

如果面试官问:“Spring Boot 启动流程是怎样的?”

回答模板:

Spring Boot 启动主要分为三个大阶段:

第一阶段:准备阶段

  • • 推断应用类型(Servlet/Reactive/普通)
  • • 加载 META-INF/spring.factories 中的配置
  • • 创建并初始化 Environment(读取配置文件)

第二阶段:创建容器阶段

  • • 根据应用类型创建 IOC 容器
  • • 将 Environment 等设置到容器

第三阶段:刷新容器阶段

  • • 这是 Spring 的核心 refresh() 方法
  • • 在这个过程中,会解析配置类、注册 Bean 定义、实例化单例 Bean
  • • 如果是 Web 项目,还会启动内嵌的 Tomcat 或 Jetty
  • • 最后发布上下文刷新完成事件

加分回答:

我特别关注过 refresh() 方法,它有 12 个核心步骤,比如 invokeBeanFactoryPostProcessors 负责执行 Bean 工厂后置处理器,finishBeanFactoryInitialization 负责实例化所有非懒加载的单例 Bean。Tomcat 的启动发生在 onRefresh() 这个方法中。

六、一张图记住启动流程

SpringApplication.run()    │    ├── 推断应用类型 (SERVLET/REACTIVE/NONE)    │    ├── 加载 spring.factories → 自动配置    │    ├── 创建 Environment → 读取配置文件    │    ├── 创建 IOC 容器    │       │    │       └── AnnotationConfig...ApplicationContext    │    └── refresh(容器)            │            ├── prepareRefresh (准备)            ├── obtainFreshBeanFactory (获取BeanFactory)            ├── prepareBeanFactory (准备BeanFactory)            ├── invokeBeanFactoryPostProcessors (执行Bean工厂后置处理器)            ├── registerBeanPostProcessors (注册Bean后置处理器)            ├── onRefresh (启动Tomcat)            ├── finishBeanFactoryInitialization (实例化单例Bean)            └── finishRefresh (完成刷新)

七、下期预告

Spring Boot 源码解析(二):@SpringBootApplication 到底干了什么?

  • • @SpringBootApplication 的三大注解
  • • @EnableAutoConfiguration 的自动配置原理
  • • @ComponentScan 的扫描范围
  • • 面试回答话术

八、互动时间

你被问过哪些 Spring Boot 源码相关的面试题?

  • • “Spring Boot 启动流程”
  • • “自动配置原理”
  • • “自定义 Starter”

评论区聊聊,下期内容优先安排你关心的问题。

我是老 J,下期见。

# 本期代码# Spring Boot 源码版本:2.7.x# 建议跟着源码走一遍