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
- 步骤 :
- obtainFreshBeanFactory() :建好厂房框架(
DefaultListableBeanFactory
),画出生产蓝图(扫描@Component
,注册BeanDefinition
)。 - prepareBeanFactory():装修厂房,装上设备(类加载器、处理器)。
- obtainFreshBeanFactory() :建好厂房框架(
- 疑问 :为什么要忽略
Aware
接口?我不是要用它们吗? - 故事 :你告诉工人,别直接把"厂长须知"(
BeanNameAware
、BeanFactoryAware
等)贴在墙上,而是交给专门的助手(BeanPostProcessor
)在合适时发给产品。 - 细节 :忽略
Aware
接口是为了避免自动注入,由ApplicationContextAwareProcessor
在初始化时手动设置,确保控制权在框架。
4. 改蓝图:BeanFactoryPostProcessor
- 步骤 :
invokeBeanFactoryPostProcessors()
。 - 故事 :设计师(
ConfigurationClassPostProcessor
)跑来说,蓝图得改,增加@Configuration
和@Bean
的生产线。 - 细节 :动态调整
BeanDefinition
,为后续生产做准备。
5. 招工人:BeanPostProcessor
- 步骤 :
registerBeanPostProcessors()
。 - 疑问 :
BeanPostProcessor
是什么?我用过@Order
是干嘛的? - 故事 :你招了一群质检员(
BeanPostProcessor
),他们会在产品生产后检查和加工(比如 AOP 包装、设置Aware
)。用@Order
排好他们的顺序,比如先检查再包装。 - 细节 :
BeanPostProcessor
在 Bean 初始化前后介入,AOP 和 Aware 都靠它实现。
6. 搭广播站:事件系统
- 步骤 :
- initMessageSource():装个翻译机(国际化)。
- initApplicationEventMulticaster() :建广播站(
ApplicationEventMulticaster
)。 - registerListeners() :招募听众(
ApplicationListener
)。
- 疑问 :事件是什么?
ApplicationListener
怎么理解? - 故事 :你建了个广播站,发布消息(事件,如
ContextRefreshedEvent
),听众(ApplicationListener
)听到后做事,比如记录日志。 - 细节 :事件是
ApplicationEvent
的实例,广播站分发给监听器,解耦逻辑。
7. 加设备:onRefresh()
- 疑问 :
onRefresh()
干嘛用?不是已经refresh()
了吗? - 故事:工厂基本建好,但你想加个特殊设备(比如 Spring Boot 的 Web 服务器),就在这步装上。
- 细节 :
onRefresh()
是子类的扩展点,不是"重新刷新",而是特定场景的初始化。
8. 生产产品:finishBeanFactoryInitialization()
- 步骤 :
preInstantiateSingletons()
。 - 疑问 :过程不够详细,三级缓存和
Aware
呢? - 故事 :生产线启动,生产单例产品(Bean):
- 拿零件:实例化对象。
- 组装:依赖注入,用三级缓存解决循环依赖(一级存成品,二级存半成品,三级存加工厂)。
- 质检 :调用
Aware
(如setBeanName
)、@PostConstruct
、初始化方法。 - 包装:AOP 代理。
- 细节 :三级缓存确保循环依赖不出错,
BeanPostProcessor
处理Aware
和代理。
9. 开业:finishRefresh()
- 步骤 :发布
ContextRefreshedEvent
。 - 疑问 :
ContextRefreshedEvent
是什么?事件有实体吗? - 故事 :工厂完工,你通过广播站喊:"开业啦!"(
ContextRefreshedEvent
),听众鼓掌。 - 细节 :
ContextRefreshedEvent
是具体的事件类,代码是new ContextRefreshedEvent(this)
,通知容器就绪。
逻辑链条:一句话总结
- 开工(new)→ 指挥(refresh)→ 建厂(BeanFactory)→ 改图(BFP)→ 招工(BPP)→ 广播(事件)→ 加装(onRefresh)→ 生产(Bean)→ 开业(finish)。
常见面试问题
- 为什么要 refresh()?
- 它是总指挥,把工厂从零建到运行。
- BeanPostProcessor 干嘛用?
- 在 Bean 生产后加工,比如 AOP 和 Aware。
- 三级缓存是啥?
- 解决循环依赖的三个"仓库":成品、半成品、加工厂。
总结
通过这个"建工厂"的故事,Spring 的启动流程不再是零散的步骤,而是一个连贯的链条。记住这条线,面试时就能娓娓道来!