Spring Boot 启动流程详解(源码级分析)
🚀 Spring Boot 启动流程详解(源码级分析)
📌 一、问题背景
在传统Spring项目中,需要大量XML配置、Servlet注册以及各种初始化工作,而Spring Boot通过一个简单的main方法即可完成整个应用启动。
看似只有一行代码,实际上Spring Boot内部完成了数百个类之间的协同工作,最终构建出完整的IOC容器并启动Web服务器。
SpringApplication.run()内部到底做了哪些事情?Bean是什么时候创建的?自动装配什么时候发生?Tomcat又是什么时候启动的?
🎯 二、核心原理
Spring Boot启动的本质,就是创建Spring IOC容器,并在容器初始化过程中完成Bean注册、自动配置、依赖注入以及Web服务器启动。
整个启动过程可以分为九个核心阶段:
- 创建SpringApplication对象
- 推断应用类型
- 加载ApplicationContext
- 准备Environment环境
- 创建IOC容器
- 执行BeanFactoryPostProcessor
- 实例化所有Bean
- 启动内嵌Tomcat
- 执行Runner回调,启动完成
Spring Boot启动流程本质就是:创建SpringApplication → 创建IOC容器 → 加载Bean → 自动装配 → 启动Tomcat → 对外提供服务。
📊 三、数据结构分析
SpringApplication负责整个启动流程,而真正存放Bean的是BeanFactory。BeanDefinition保存Bean的元数据,真正实例化完成后才会变成Bean对象。
🔥 四、算法分析
SpringApplication.run()可以抽象为下面几个步骤:
真正最重要的方法其实只有一个,那就是refresh()。
Spring Boot启动流程,其实80%的工作都是在AbstractApplicationContext.refresh()里面完成的。
🚀 五、执行流程
💡 六、实际案例
案例一:SpringApplication.run()
进入run方法后,首先创建SpringApplication对象,并推断当前应用属于Servlet、Reactive还是普通Java程序。
案例二:refresh()刷新容器
refresh()是整个Spring生命周期的核心,它负责BeanDefinition加载、Bean后处理器注册、Bean实例化以及容器最终初始化。
案例三:Bean创建流程
Tomcat启动并不是SpringApplication.run()开始时就启动,而是在refresh()阶段的onRefresh()过程中启动内嵌Web服务器,之后才开始监听HTTP请求。
✅ 七、优缺点分析
| 优点 | 说明 |
|---|---|
| 自动配置 | 减少大量XML配置,提高开发效率 |
| 内嵌Web服务器 | 无需部署WAR即可运行 |
| IOC生命周期完善 | 统一管理Bean生命周期和依赖关系 |
| 扩展能力强 | 支持Starter、自动装配、监听器、事件机制等 |
🎯 八、面试常见问题
main方法中的SpringApplication.run()就是整个Spring Boot应用的启动入口。
AbstractApplicationContext.refresh()。IOC容器创建、Bean实例化、自动装配以及Tomcat启动几乎都围绕refresh()展开。
BeanDefinition加载完成后,在refresh()的finishBeanFactoryInitialization()阶段实例化所有非懒加载单例Bean。
Tomcat并不是main方法启动时立即启动,而是在refresh()过程中调用onRefresh()创建并启动内嵌Tomcat,随后开始监听HTTP端口。
自动装配依赖@EnableAutoConfiguration加载AutoConfiguration配置类,在refresh()过程中注册BeanDefinition,并最终完成Bean实例化和依赖注入。
📌 九、总结
Spring Boot启动流程可以浓缩为下面九个步骤:
对于高级开发者而言,需要重点掌握SpringApplication.run()、ApplicationContext创建、refresh()生命周期、Bean实例化、自动装配原理以及Tomcat启动时机。其中,refresh()方法是整个Spring Boot启动流程的核心,也是阅读Spring源码和面试时最值得深入理解的部分。
相关文章
-
程序员面试技术面和HR面试,最后要问什么问题?
程序员面试技术面和HR面试,最后要问什么问题?
NEW个对象 2026-06-14
-
如果打印日志遇到瓶颈该怎么办?
如果打印日志遇到瓶颈该怎么办? 1、减少日志的输出 2、降低日志输出级别 3、日志做模块拆分,不同的模块打印到不同的文件里 4、异步日志 5、配置文件大小,当超过文件大小的时候,会创建一个新文件。
NEW个对象 2024-11-03
-
秒杀系统线程池削峰,包括代码实现
线程池削峰的本质是通过控制系统同时处理请求的数量,将瞬时洪峰流量转化为平稳流量。对于秒杀场景而言,线程池相当于一个“缓冲池”,大量请求先进入队列排队,再由固定数量的工作线程逐步处理,从而保护数据库、Redis、MQ等后端资源不被瞬时流量冲垮。
NEW个对象 2026-06-13