跳到正文
Elaine Blog
返回

ApplicationContext 启动主线:读懂 refresh 模板流程

Spring 生态与源码

阅读 Spring 启动源码时,以 AbstractApplicationContext.refresh() 为主线,不要从包目录逐类翻译。它是一套模板流程:准备容器、加工定义、注册基础设施、创建单例、发布完成事件。

Table of contents

Open Table of contents

用最小上下文设置断点

MiniBootSample下载只注册一个配置类并读取一个 Bean:

mvn -Dtest=SpringSourceLabTest#minimalBootCreatesAndClosesAContext test

AnnotationConfigApplicationContext.refresh() 设置断点,记录线程名、BeanDefinition 数量和关键处理器数量。最小入口比完整 Boot 应用更容易看到因果关系。

refresh 的六个阶段

  1. 准备 Context 状态、属性源和启动时间;
  2. 获得并准备 BeanFactory;
  3. 执行 BeanFactoryPostProcessor,允许修改 BeanDefinition;
  4. 注册 BeanPostProcessor、事件广播器等基础设施;
  5. finishBeanFactoryInitialization 创建剩余非懒加载单例;
  6. 发布 Context 已刷新事件。

如果中途失败,refresh 会销毁已创建单例并重置状态。启动异常不能只看最外层 BeanCreationException,要沿最深 cause 找到第一个业务配置错误。

模板方法为什么重要

AbstractApplicationContext 固定总流程,子类在加载 BeanDefinition、准备环境等位置提供差异。这就是模板方法模式:父类控制算法骨架,子类实现局部步骤。

源码阅读时把方法分为“主线阶段”和“阶段内部细节”。第一轮只写一页调用图;第二轮再针对配置解析、实例化或事件选择一条支线。

BeanFactory 扩展必须提前执行

BeanFactoryPostProcessor 修改的是配方,所以必须在普通单例创建前执行。BeanPostProcessor 加工的是对象,所以必须在目标 Bean 初始化前注册。顺序反了,早期 Bean 就会绕过代理和注解处理。

这也是“不应在后置处理器注册期间随意 getBean”的原因:提前创建会产生不完整生命周期。

下一步

阅读Bean 生命周期与后置处理器,沿单个对象追踪实例化、注入、初始化、代理和销毁。


分享这篇文章:

上一篇
手写最小 IoC 容器
下一篇
Bean 生命周期与后置处理器