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 启动时只做两件核心工作构建 IoC 容器收集所有 Bean 的BeanDefinition按规则创建对象并完成依赖注入。挂载 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. 怎么注册到 TomcatTomcat 启动后会回调所有ServletContextInitializerServletRegistrationBean就把DispatcherServlet添加到 Tomcat 的ServletContext中并映射到/。最终效果http://host:port/xxx→ Tomcat → DispatcherServlet → 你的 Controller 方法。没有魔法Tomcat 被包装成一个普通 BeanServletRegistrationBean只是一个“注册器”。三、核心思想依赖注入才是灵魂无论看多少遍 Spring 源码请记住这条主线配置信息注解/配置类 → BeanDefinition元数据 → Bean 实例 → 依赖注入三个最关键的组件BeanDefinitionBean 的信息记录类名、作用域、构造参数、依赖关系等。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 的时候。简化流程getBean(beanName)→ 从beanDefinitionMap取出 BeanDefinition。根据 BeanDefinition 实例化对象构造器或工厂方法。执行 BeanPostProcessor 的钩子其中AutowiredAnnotationBeanPostProcessor扫描Autowired字段/方法从容器取出依赖并反射赋值。执行初始化方法PostConstruct、InitializingBean。返回成品 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 ApplicationListenerMyCustomEvent { 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 到底是怎么“切”进去的