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# 建议跟着源码走一遍
夜雨聆风