Spring 启动流程:比喻表达

Spring 启动流程:从零到一的故事

Spring 的启动流程(以 AnnotationConfigApplicationContext 为例)就像一个工厂从空地到生产线的搭建过程。面试中常被问到这个流程,但记不住怎么办?让我们用一条逻辑链条,把它讲成一个故事,帮助你记住每个步骤。

时序图:故事的蓝图

先看一张简化的时序图(用 Mermaid 语法,可在 Mermaid Live Editor 渲染):

sequenceDiagram participant U as 用户 participant AC as ApplicationContext participant BF as BeanFactory participant BFP as BeanFactoryPostProcessor participant BPP as BeanPostProcessor participant EM as EventMulticaster participant EL as Listener participant BEAN as Bean U->>AC: new ApplicationContext(AppConfig) AC->>AC: refresh() AC->>BF: 创建并配置工厂 BF->>BFP: 调整蓝图 BF->>BPP: 准备生产线工人 AC->>EM: 搭建广播站 EM->>EL: 招募听众 BF->>BEAN: 生产产品 AC->>EM: 宣布开业 U-->>AC: 工厂运行

故事线:Spring 工厂的诞生

想象你是一个工厂老板,要用 Spring 建一个智能工厂。以下是整个流程的逻辑链条:

1. 开工:创建工厂大门 (new ApplicationContext)

  • 代码new AnnotationConfigApplicationContext(AppConfig.class)
  • 故事 :你买了块地,立了个牌子"Spring 工厂",大门上写着配置信息(AppConfig)。
  • 细节 :初始化了一个空的 ApplicationContext,准备进入正题。

2. 总指挥:启动工厂 (refresh())

  • 疑问 :为什么要 refresh()?有什么深意?
  • 故事 :你按下启动按钮(refresh()),工厂开始从零到一地搭建。
  • 深意refresh() 是总指挥,负责把所有零件(Bean 定义、事件系统等)组装成一个完整的工厂。它确保一切按顺序发生,避免混乱。
  • 细节 :这是 AbstractApplicationContext 的核心方法,包含以下所有步骤。

3. 建厂房:创建并配置 BeanFactory

  • 步骤
    1. obtainFreshBeanFactory() :建好厂房框架(DefaultListableBeanFactory),画出生产蓝图(扫描 @Component,注册 BeanDefinition)。
    2. prepareBeanFactory():装修厂房,装上设备(类加载器、处理器)。
  • 疑问 :为什么要忽略 Aware 接口?我不是要用它们吗?
  • 故事 :你告诉工人,别直接把"厂长须知"(BeanNameAwareBeanFactoryAware 等)贴在墙上,而是交给专门的助手(BeanPostProcessor)在合适时发给产品。
  • 细节 :忽略 Aware 接口是为了避免自动注入,由 ApplicationContextAwareProcessor 在初始化时手动设置,确保控制权在框架。

4. 改蓝图:BeanFactoryPostProcessor

  • 步骤invokeBeanFactoryPostProcessors()
  • 故事 :设计师(ConfigurationClassPostProcessor)跑来说,蓝图得改,增加 @Configuration@Bean 的生产线。
  • 细节 :动态调整 BeanDefinition,为后续生产做准备。

5. 招工人:BeanPostProcessor

  • 步骤registerBeanPostProcessors()
  • 疑问BeanPostProcessor 是什么?我用过 @Order 是干嘛的?
  • 故事 :你招了一群质检员(BeanPostProcessor),他们会在产品生产后检查和加工(比如 AOP 包装、设置 Aware)。用 @Order 排好他们的顺序,比如先检查再包装。
  • 细节BeanPostProcessor 在 Bean 初始化前后介入,AOP 和 Aware 都靠它实现。

6. 搭广播站:事件系统

  • 步骤
    1. initMessageSource():装个翻译机(国际化)。
    2. initApplicationEventMulticaster() :建广播站(ApplicationEventMulticaster)。
    3. registerListeners() :招募听众(ApplicationListener)。
  • 疑问 :事件是什么?ApplicationListener 怎么理解?
  • 故事 :你建了个广播站,发布消息(事件,如 ContextRefreshedEvent),听众(ApplicationListener)听到后做事,比如记录日志。
  • 细节 :事件是 ApplicationEvent 的实例,广播站分发给监听器,解耦逻辑。

7. 加设备:onRefresh()

  • 疑问onRefresh() 干嘛用?不是已经 refresh() 了吗?
  • 故事:工厂基本建好,但你想加个特殊设备(比如 Spring Boot 的 Web 服务器),就在这步装上。
  • 细节onRefresh() 是子类的扩展点,不是"重新刷新",而是特定场景的初始化。

8. 生产产品:finishBeanFactoryInitialization()

  • 步骤preInstantiateSingletons()
  • 疑问 :过程不够详细,三级缓存和 Aware 呢?
  • 故事 :生产线启动,生产单例产品(Bean):
    1. 拿零件:实例化对象。
    2. 组装:依赖注入,用三级缓存解决循环依赖(一级存成品,二级存半成品,三级存加工厂)。
    3. 质检 :调用 Aware(如 setBeanName)、@PostConstruct、初始化方法。
    4. 包装:AOP 代理。
  • 细节 :三级缓存确保循环依赖不出错,BeanPostProcessor 处理 Aware 和代理。

9. 开业:finishRefresh()

  • 步骤 :发布 ContextRefreshedEvent
  • 疑问ContextRefreshedEvent 是什么?事件有实体吗?
  • 故事 :工厂完工,你通过广播站喊:"开业啦!"(ContextRefreshedEvent),听众鼓掌。
  • 细节ContextRefreshedEvent 是具体的事件类,代码是 new ContextRefreshedEvent(this),通知容器就绪。

逻辑链条:一句话总结

  • 开工(new)→ 指挥(refresh)→ 建厂(BeanFactory)→ 改图(BFP)→ 招工(BPP)→ 广播(事件)→ 加装(onRefresh)→ 生产(Bean)→ 开业(finish)

常见面试问题

  1. 为什么要 refresh()?
    • 它是总指挥,把工厂从零建到运行。
  2. BeanPostProcessor 干嘛用?
    • 在 Bean 生产后加工,比如 AOP 和 Aware。
  3. 三级缓存是啥?
    • 解决循环依赖的三个"仓库":成品、半成品、加工厂。

总结

通过这个"建工厂"的故事,Spring 的启动流程不再是零散的步骤,而是一个连贯的链条。记住这条线,面试时就能娓娓道来!

相关推荐
oden25 分钟前
AI服务商切换太麻烦?一个AI Gateway搞定监控、缓存和故障转移(成本降40%)
后端·openai·api
李慕婉学姐1 小时前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
m0_740043731 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
招风的黑耳2 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
Miss_Chenzr3 小时前
Springboot优卖电商系统s7zmj(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
期待のcode3 小时前
Springboot核心构建插件
java·spring boot·后端
2501_921649493 小时前
如何获取美股实时行情:Python 量化交易指南
开发语言·后端·python·websocket·金融
serendipity_hky3 小时前
【SpringCloud | 第5篇】Seata分布式事务
分布式·后端·spring·spring cloud·seata·openfeign
五阿哥永琪4 小时前
Spring Boot 中自定义线程池的正确使用姿势:定义、注入与最佳实践
spring boot·后端·python
Victor3564 小时前
Netty(16)Netty的零拷贝机制是什么?它如何提高性能?
后端