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 的启动流程不再是零散的步骤,而是一个连贯的链条。记住这条线,面试时就能娓娓道来!

相关推荐
Asthenia04124 分钟前
为什么把私钥写在代码里是一个致命错误
后端
程序员一诺10 分钟前
【Flask开发】嘿马文学web完整flask项目第2篇:2.用户认证,Json Web Token(JWT)【附代码文档】
后端·python·flask·框架
Asthenia041214 分钟前
如何在 Java 中正确判空 BigDecimal 等数据类型
后端
冷琅辞27 分钟前
Swift语言的跨平台开发
开发语言·后端·golang
Asthenia041241 分钟前
Pandas期末备考:常见问题解析
后端
今夜有雨.1 小时前
使用C++实现HTTP服务
开发语言·网络·c++·后端·网络协议·tcp/ip·http
东方苾梦1 小时前
Lua语言的安全开发
开发语言·后端·golang
Asthenia04121 小时前
Spring Boot @Conditional 注解分析与实际业务场景应用
后端
慕离桑1 小时前
HTML语言的数据可视化
开发语言·后端·golang
我命由我123451 小时前
C++ - 头文件基础(常用标准库头文件、自定义头文件、头文件引入方式、防止头文件重复包含机制)
服务器·c语言·开发语言·c++·后端·visualstudio·visual studio code