news 2026/6/11 16:27:57

JavaWeb 造轮者视角:Spring Boot 启动核心思想与完整链路解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb 造轮者视角:Spring Boot 启动核心思想与完整链路解析

作者:CodeStats
一个专注分享Java底层原理、自研框架实战干货的技术博主。如果觉得内容实用,欢迎点赞 + 收藏 + 关注

📚 相关阅读(造轮者必备)

本文的思考,源于我自己动手手写 Tomcat + 自研 IoC 容器的经历。如果你也对“造轮子”感兴趣,推荐搭配阅读:

  • 手写Tomcat + 自研IoC:我用AI一周实现了一个完整的Java Web框架-CSDN博客
    这篇文章从零实现了一个极简 Web 服务器和依赖注入容器,与本文的 Spring Boot 原理形成“实战 vs 框架”的对照。

  • 从 Spring 到 Spring Boot 再到 Spring Cloud:自动配置原理与动态代理深度解析(附自研框架 Codestats 实战)-CSDN博客
    帮你建立从 Spring 基础到微服务生态的完整认知链路。

📑 目录

  • 一、一句话说清:Spring Boot 启动就干两件事

  • 二、内嵌 Tomcat 和 DispatcherServlet 如何搭上线

  • 三、核心思想:依赖注入才是灵魂

  • 四、BeanFactoryPostProcessor vs BeanPostProcessor(区别 + 生效时机)

  • 五、12 步 refresh() 的“分段解读”

  • 六、依赖注入什么时候真正发生?

  • 七、事件机制是如何实现的

  • 八、总结:从配置到请求,链路终于通了

一、一句话说清:Spring Boot 启动就干两件事

从造轮者的角度看,Spring Boot 启动时只做两件核心工作:

  1. 构建 IoC 容器:收集所有 Bean 的(BeanDefinition),按规则创建对象并完成依赖注入。

  2. 挂载 Web 能力:启动内嵌 Web 服务器(如 Tomcat),并将请求分发核心 DispatcherServlet 注册进去,让它能把 HTTP 请求转给已经建好的 Controller。

这两件事有严格顺序:先有 IoC 容器,后有 Web 服务器。因为服务器需要的组件(如 Controller、HandlerMapping)都来自容器。

最朴实的比喻:先把家里收拾利索(所有 Bean 造好、依赖引好),再开门营业(启动 Tomcat,接收请求)。

二、内嵌 Tomcat 和 DispatcherServlet 如何搭上线?

2.1 文字说明

这一步是许多人的盲区,其实拆开来看非常简单:

1. Tomcat 是谁启动的?
Spring Boot 在refresh()的第 9 步onRefresh()中,调用ServletWebServerApplicationContext#onRefresh()createWebServer()→ 实例化 Tomcat,绑定端口,启动。

2. DispatcherServlet 是谁创建的?
DispatcherServletAutoConfiguration自动配置类中有一个@Bean返回DispatcherServlet实例,同时还会创建ServletRegistrationBean(实现了ServletContextInitializer接口)。

3. 怎么注册到 Tomcat?
Tomcat 启动后会回调所有ServletContextInitializerServletRegistrationBean就把DispatcherServlet添加到 Tomcat 的ServletContext中,并映射到"/"

最终效果:http://host:port/xxx→ Tomcat → DispatcherServlet → 你的 Controller 方法。

没有魔法:Tomcat 被包装成一个普通 Bean,ServletRegistrationBean只是一个“注册器”。

三、核心思想:依赖注入才是灵魂

无论看多少遍 Spring 源码,请记住这条主线:

配置信息(注解/配置类) → BeanDefinition(元数据) → Bean 实例 → 依赖注入

三个最关键的组件:

  • BeanDefinition:Bean 的信息,记录类名、作用域、构造参数、依赖关系等。

  • BeanFactoryPostProcessor:这阶段动手脚(修改 BeanDefinition)。例如ConfigurationClassPostProcessor解析@ComponentScan@Import@Bean

  • BeanPostProcessor:在 Bean 实例化之后,对“成品”进行加工(@Autowired注入、AOP 代理)。

很多初学者混淆后两者,下一节专门对比。

四、BeanFactoryPostProcessor vs BeanPostProcessor(区别 + 生效时机)

接口操作对象执行阶段典型例子
BeanFactoryPostProcessorBeanDefinition(元数据)实例化任何 Bean之前refresh()第 5 步invokeBeanFactoryPostProcessorsConfigurationClassPostProcessor(解析注解、自动配置)
BeanPostProcessorBean实例(已经 new 出来的对象)实例化之后,初始化前后;第 6 步注册,实际调用在getBean()过程中AutowiredAnnotationBeanPostProcessor(处理@Autowired

一句话总结

BeanFactoryPostProcessor改图纸,BeanPostProcessor修成品。
前者在盖楼前改设计图,后者在楼盖好后刷墙布线。

自动配置为什么不用写<bean>?因为ConfigurationClassPostProcessor读到@SpringBootApplication后,主动去META-INF/.../AutoConfiguration.imports里拉了一堆配置类,全变成了BeanDefinition

五、12 步 refresh() 的“分段解读”(剥去繁琐,只留骨架)

AbstractApplicationContext.refresh()共 12 步,分四个阶段理解:

🔹 阶段一:准备 & 获取 BeanFactory(第 1~4 步)

  • prepareRefresh:校验必要属性。

  • obtainFreshBeanFactory创建DefaultListableBeanFactory(存 BeanDefinition 的仓库)。

  • prepareBeanFactory:配置类加载器、表达式解析器,加几个系统级 BeanPostProcessor。

  • postProcessBeanFactory:扩展钩子(Web 环境注册 Scope)。

产出:一个空的、配置好的 BeanFactory。

🔹 阶段二:加载 & 修改 BeanDefinition(第 5 步)

  • invokeBeanFactoryPostProcessors执行所有 BeanFactoryPostProcessor
    ConfigurationClassPostProcessor解析主类上的@ComponentScan@Import@Bean及自动配置,生成大量新 BeanDefinition 并注册。

产出:beanDefinitionMap里填满了所有 Bean 的定义信息。

🔹 阶段三:注册“装修队”(第 6 步)

  • registerBeanPostProcessors:找出所有BeanPostProcessor,实例化并存入工厂列表。
    这些“装修队”会在每个 Bean 实例化后被调用,完成@Autowired注入、AOP 等。

注意:只注册,不调用。真正调用在getBean()过程中。

🔹 阶段四:基础设施 & 事件 & 实例化(第 7~12 步)

  • initMessageSource:国际化。

  • initApplicationEventMulticaster:事件广播器。

  • onRefresh启动内嵌 Tomcat(见第二部分)。

  • registerListeners:注册事件监听器。

  • finishBeanFactoryInitialization实例化所有非懒加载的单例 Bean,过程中触发 BeanPostProcessor 完成依赖注入。

  • finishRefresh:发布ContextRefreshedEvent,启动完成。

最核心的是finishBeanFactoryInitialization—— 把图纸变成真实对象,并灌入依赖。

六、依赖注入什么时候真正发生?

答案:在finishBeanFactoryInitialization()中调用getBean()创建每个单例 Bean 的时候。

简化流程:

  1. getBean(beanName)→ 从beanDefinitionMap取出 BeanDefinition。

  2. 根据 BeanDefinition 实例化对象(构造器或工厂方法)。

  3. 执行 BeanPostProcessor 的钩子,其中AutowiredAnnotationBeanPostProcessor扫描@Autowired字段/方法,从容器取出依赖并反射赋值。

  4. 执行初始化方法(@PostConstructInitializingBean)。

  5. 返回成品 Bean 存入singletonObjects缓存。

依赖注入不是独立的一步,而是嵌在getBean()过程中,由 BeanPostProcessor 驱动。

七、事件机制是如何实现的(附简单代码示例)

Spring 的事件机制基于发布-订阅模式,允许 Bean 之间解耦通信。

核心组件

  • 事件(ApplicationEvent):继承ApplicationEvent,封装信息。

  • 监听器(ApplicationListener):监听特定事件,执行逻辑。

  • 广播器(ApplicationEventMulticaster):负责派发事件给所有匹配的监听器。

  • 发布者:注入ApplicationEventPublisher,调用publishEvent()

简单代码示例

java

// 1. 自定义事件 public class MyCustomEvent extends ApplicationEvent { private final String message; public MyCustomEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; } } // 2. 监听器(方式一:实现接口) @Component public class MyEventListener implements ApplicationListener<MyCustomEvent> { @Override public void onApplicationEvent(MyCustomEvent event) { System.out.println("收到事件:" + event.getMessage()); } } // 或者方式二:使用 @EventListener(更简洁) @Component public class AnotherListener { @EventListener public void handleEvent(MyCustomEvent event) { System.out.println("@EventListener 收到:" + event.getMessage()); } } // 3. 发布事件(任意 Bean 中) @Service public class EventPublisherService { @Autowired private ApplicationEventPublisher publisher; public void send(String msg) { publisher.publishEvent(new MyCustomEvent(this, msg)); } }

执行流程

  • Spring 在initApplicationEventMulticaster()中创建广播器(默认为SimpleApplicationEventMulticaster)。

  • registerListeners()将所有ApplicationListenerBean 注册到广播器。

  • 调用publishEvent()时,广播器同步或异步派发事件给所有监听器。

  • finishRefresh()最后还会发布ContextRefreshedEvent,通知容器已启动。

事件机制完全依赖 IoC 容器:监听器本身也是 Bean,广播器从容器获取监听器列表。这正是依赖注入思想的延伸。

八、总结:从配置到请求,链路终于通了

最简化时序链:

text

主类 @SpringBootApplication ↓ (解析阶段) ConfigurationClassPostProcessor 读取自动配置、扫描 @Component ↓ (生成 BeanDefinition) beanDefinitionMap 塞满Bean信息 ↓ (finishBeanFactoryInitialization) 实例化每个 Bean,通过 BeanPostProcessor 完成依赖注入 ↓ (onRefresh) Tomcat 启动,DispatcherServlet 注册 ↓ HTTP 请求 → Tomcat → DispatcherServlet → 你的 Controller

很多人觉得 Spring Boot 复杂,是因为把“自动配置”、“依赖注入”、“Web 服务器启动”、“事件机制”等多件事搅在一起。其实它们是有序串联的:先有 Bean 定义,再有 Bean 实例,再有依赖填充和事件广播器,最后挂上 Web 服务器

如果你能画出这个顺序,再回头看refresh()的 12 步,每一步都有它明确的位置和作用。

本文以“造轮者”的视角,只希望用最朴素的逻辑帮你串起整个启动流程。
如果觉得有帮助,别忘了点赞、收藏、加关注,我是 CodeStats,下篇聊 AOP 到底是怎么“切”进去的

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 16:26:56

ComfyUI-LTXVideo完全指南:在ComfyUI中轻松生成AI视频的终极解决方案

ComfyUI-LTXVideo完全指南&#xff1a;在ComfyUI中轻松生成AI视频的终极解决方案 【免费下载链接】ComfyUI-LTXVideo LTX-Video Support for ComfyUI 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-LTXVideo 你是否渴望在ComfyUI中体验最先进的AI视频生成技…

作者头像 李华
网站建设 2026/6/11 16:24:51

RTranslator大模型下载3步优化方案:从卡顿到流畅的完整指南

RTranslator大模型下载3步优化方案&#xff1a;从卡顿到流畅的完整指南 【免费下载链接】RTranslator Open source real-time translation app for Android that runs locally 项目地址: https://gitcode.com/GitHub_Trending/rt/RTranslator 想象一下这样的场景&#x…

作者头像 李华
网站建设 2026/6/11 16:23:52

Harness Engineering 是什么?和提示词工程、上下文工程有什么关系?

Harness Engineering 是什么&#xff1f;和提示词工程、上下文工程有什么关系&#xff1f;Harness Engineering 是什么&#xff1f;和提示词工程、上下文工程有什么关系&#xff1f;0. 一个让你秒懂的比喻1. 概念演进&#xff1a;三个范式的“三级跳”第一阶段&#xff08;2022…

作者头像 李华
网站建设 2026/6/11 16:21:52

如何在Windows平台快速实现专业级中文排版:PingFangSC字体完整指南

如何在Windows平台快速实现专业级中文排版&#xff1a;PingFangSC字体完整指南 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件&#xff0c;包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 告别Windows系统默认中文字…

作者头像 李华
网站建设 2026/6/11 16:18:51

华硕笔记本性能调校革命:G-Helper完整指南与实战教程

华硕笔记本性能调校革命&#xff1a;G-Helper完整指南与实战教程 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Exp…

作者头像 李华
网站建设 2026/6/11 16:16:32

2026在线去本地视频水印工具推荐:免费去视频水印实用教程

日常刷短视频、整理素材、自制剪辑内容时&#xff0c;很多人都会遇到本地视频自带水印、角标、飘字遮挡画面的问题。想要清理水印、还原干净画质&#xff0c;又不想下载臃肿的客户端软件、不想付费开通会员、担心素材上传泄露隐私&#xff0c;这时候在线去本地视频水印工具就成…

作者头像 李华