# refresh详解

作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)
相关源码参考: Spring源码中文注释仓库5.3.x分支 (opens new window)


经过上一章分析,不同类型的 IOC 容器在准备阶段和加载方式上略有差异,但最终都会调用抽象父类 AbstractApplicationContextrefresh() 方法进行容器刷新。下面是整体流程与核心逻辑。

ClassPathXmlApplicationContext.refresh()
       │
       └─ 调用父类 AbstractApplicationContext.refresh()
               │
               ├─ 同步锁,防止并发刷新
               │
               ├─ 【步骤1】prepareRefresh()
               │       ├─ 初始化环境变量(Environment)
               │       ├─ 记录启动时间戳
               │       └─ 重置刷新状态相关标志
               │
               ├─ 【步骤2 创建容器 (下一步详解)obtainFreshBeanFactory()
               │       ├─ 调用子类的 refreshBeanFactory(),重新加载 Bean 定义
               │       └─ 返回新的 ConfigurableListableBeanFactory 实例
               │
               ├─ 【步骤3】prepareBeanFactory(beanFactory)
               │       ├─ 设置 ClassLoader
               │       ├─ 添加 BeanPostProcessor(如 ApplicationContextAwareProcessor)
               │       └─ 配置 PropertyEditor 注册
               │
               ├─ 【步骤4】postProcessBeanFactory(beanFactory)
               │       └─ 子类可重写扩展(通常空实现)
               │
               ├─ 【步骤5】invokeBeanFactoryPostProcessors(beanFactory)
               │       └─ 调用 BeanFactoryPostProcessor,支持 @Configuration、PropertySource 等处理
               │
               ├─ 【步骤6】registerBeanPostProcessors(beanFactory)
               │       └─ 注册 BeanPostProcessor,用于拦截 Bean 初始化流程(AOP、@Autowired 等)
               │
               ├─ 【步骤7】initMessageSource()
               │       └─ 初始化国际化资源管理器
               │
               ├─ 【步骤8】initApplicationEventMulticaster()
               │       └─ 初始化事件广播器,管理事件发布与监听
               │
               ├─ 【步骤9】onRefresh()
               │       └─ 子类模板方法,完成特定容器的刷新逻辑(如初始化生命周期Bean)
               │
               ├─ 【步骤10】registerListeners()
               │       └─ 注册事件监听器
               │
               ├─ 【步骤11】finishBeanFactoryInitialization(beanFactory)
               │       ├─ 初始化非懒加载单例 Bean
               │       └─ 完成 Bean 实例化和依赖注入
               │
               ├─ 【步骤12】finishRefresh()
               │       ├─ 发布容器刷新完成事件
               │       └─ 清理启动相关状态
               │
               └─ 异常处理
                       ├─ 关闭已创建 Bean
                       └─ 取消刷新状态,抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

核心设计与关键点

  • 模板方法模式refresh() 定义容器刷新完整流程,部分步骤留给子类实现。
  • 线程安全:通过同步锁保证刷新过程不被多线程干扰。
  • BeanFactory 重载:调用子类的 refreshBeanFactory(),确保每次刷新基于干净的 BeanFactory。
  • 多阶段处理
    1. 准备环境:prepareRefresh()
    2. 创建容器:obtainFreshBeanFactory()
    3. 配置 BeanFactory:prepareBeanFactory()
    4. 后处理 BeanFactory:postProcessBeanFactory()
    5. 调用 BeanFactoryPostProcessor:invokeBeanFactoryPostProcessors()
    6. 注册 BeanPostProcessor:registerBeanPostProcessors()
    7. 初始化核心组件:initMessageSource()initApplicationEventMulticaster()
    8. 子类特定刷新:onRefresh()
    9. 注册事件监听器:registerListeners()
    10. 初始化非懒加载单例 Bean:finishBeanFactoryInitialization()
    11. 完成刷新:finishRefresh()
      • 事件发布:刷新完成后发送事件,供组件监听容器生命周期。
      • 异常安全:刷新异常时销毁已创建 Bean,保持容器状态一致。

refresh() 方法的核心作用是:

  • 在创建新的 IOC 容器之前,如果已有旧容器存在,则先销毁并关闭旧容器,保证刷新后使用的是新创建的容器。
  • 通过刷新流程,完成容器的初始化和 Bean 配置资源的加载。
  • 该过程类似于对 IOC 容器的“重启”,确保新容器的状态是干净且完整的。

这样设计,保证了 Spring 容器的灵活性和可复用性,方便对容器进行多次刷新和重新加载。


# 1. prepareRefresh

容器准备阶段,准备刷新,设置环境、时间戳、标志位等, 比较简单, 读者自己阅读下相关源码。

# 2. obtainFreshBeanFactory

该方法用于获取或重建 IOC 容器,是 IOC 容器的核心实现

# 核心流程

  1. 销毁旧容器
    • 如果当前容器已有 BeanFactory,先销毁已有 Bean 并关闭旧 BeanFactory,释放资源,保证容器干净重建。
  2. 创建新 BeanFactory
    • 构造 DefaultListableBeanFactory 实例,作为当前容器的 BeanFactory。
  3. 配置 BeanFactory
    • 设置序列化 ID (setSerializationId)
    • 配置启动分析器 (setApplicationStartup)
    • 根据容器配置自定义 BeanFactory(循环依赖、允许覆盖同名 Bean 等)
  4. 加载 Bean 定义
    • 调用 loadBeanDefinitions(beanFactory),加载 XML 配置、注解扫描、Java 配置类等 Bean 定义。
  5. 更新容器引用
    • 将新创建并初始化的 BeanFactory 赋值给当前上下文的 beanFactory 字段。
ClassPathXmlApplicationContext.refresh()
    │
    └─ AbstractApplicationContext.refresh()
            │
            ├─ 【步骤2】obtainFreshBeanFactory()
            │       │
            │       ├─ 调用 refreshBeanFactory()
            │       │       │
            │       │       ├─ (AbstractRefreshableApplicationContext 实现)
            │       │       │
            │       │       ├─ if (hasBeanFactory())
            │       │       │       ├─ destroyBeans()       # 销毁已有 Bean 实例
            │       │       │       └─ closeBeanFactory()   # 关闭旧 BeanFactory
            │       │       │
            │       │       ├─ createBeanFactory()
            │       │       │       └─ 创建新的 DefaultListableBeanFactory
            │       │       │
            │       │       ├─ beanFactory.setSerializationId(getId())    # 设置序列化ID
            │       │       ├─ beanFactory.setApplicationStartup(...)      # 设置启动分析器
            │       │       ├─ customizeBeanFactory(beanFactory)            # 自定义 BeanFactory(循环依赖、覆盖等)
            │       │       ├─ (下一步详解) loadBeanDefinitions(beanFactory)             # 加载 Bean 定义(XML、注解、Java配置)
            │       │       └─ this.beanFactory = beanFactory               # 设置当前上下文的 BeanFactory
            │       │
            │       └─ 返回新创建的 beanFactory
            │
            └─ 后续步骤(prepareBeanFactory...)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

按照上述流程具体解析下源码:

# 载入配置路径

loadBeanDefinitions() 负责将配置文件转为 BeanDefinition:

  1. 创建读取器
    • XmlBeanDefinitionReader 与当前 BeanFactory 绑定。
  2. 配置读取器
    • 设置环境变量(profile)、资源加载器、实体解析器(DTD/XSD 校验)。
  3. 初始化读取器扩展点
    • initBeanDefinitionReader() 可由子类重写。
  4. 加载配置
    • 优先尝试 Resource[] configResources,否则使用 String[] configLocations(XML 路径)。
AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory)
    │
    ├─ 创建 XmlBeanDefinitionReader(beanFactory)
    ├─ 配置 reader 属性(Environment、ResourceLoader、EntityResolver)
    ├─ initBeanDefinitionReader(reader)
    └─ loadBeanDefinitions(reader)
          ├─ getConfigResources()null
          └─ getConfigLocations() → XML 路径数组
                ↓
          reader.loadBeanDefinitions(configLocations)
1
2
3
4
5
6
7
8
9
10

# 路径处理策略

reader.loadBeanDefinitions(String... locations) 流程:

  1. 批量加载:遍历每个路径。
  2. 路径解析
    • ResourcePatternResolver 支持通配符 (classpath*:)
    • 普通路径直接解析为单个 Resource。
  3. 加载 Resource
    • 委托给 XmlBeanDefinitionReader,解析 XML 并注册 BeanDefinition。
AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory)
    │
    ├─  ... 看上节 ...
    │
    │
    └─ 从这开始分析本节 AbstractXmlApplicationContext.loadBeanDefinitions(reader)
                                        
                       reader.loadBeanDefinitions(configLocations)
                          │
                          └─ AbstractBeanDefinitionReader.loadBeanDefinitions(String... locations)
                                ├─ 遍历每个 location
                                │
                                ├─ 调用 loadBeanDefinitions(String location)
                                │     │
                                │     ├─ 判断资源加载器是否实现 ResourcePatternResolver?
                                │     │     ├─ 是 → 使用 getResources(location) 获取多个 Resource
                                │     │     │         └─ PathMatchingResourcePatternResolver 默认支持
                                │     │     └─ 否 → 使用 getResource(location) 解析单个 Resource
                                │     │
                                │     └─ 对每个 Resource 调用 loadBeanDefinitions(Resource resource) 
                                │           └─ (下一步详解)委托给 XmlBeanDefinitionReader 解析 XML 并注册 BeanDefinition
                                │
                                └─ 返回加载的 BeanDefinition 总数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 解析 XML 内容

  1. 防止循环加载
    • 使用 ThreadLocal<Set<EncodedResource>> 记录当前线程正在加载的资源。
  2. 封装资源
    • EncodedResource 封装 Resource + encoding(如 UTF-8)。
  3. 解析入口
    • 通过 InputSource 标准化 SAX 输入,调用 doLoadBeanDefinitions()
XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)
    │
    └─ new EncodedResource(resource)loadBeanDefinitions(EncodedResource encodedResource)
        │
        ├─ 获取当前线程正在加载的资源 Set<EncodedResource>
        │
        ├─ 检查是否已加载(避免循环加载)←────┐
        │     └─ 若已存在则抛出异常              │
        │                                        │
        ├─ try-with-resources 打开 InputStream   │
        │     └─ InputSource inputSource ←───────┘
        │             ├─ 设置 encoding(如有)
        │
        ├─ (下一步详解) 调用 doLoadBeanDefinitions(inputSource, resource)
        │     └─ 执行真正的 XML 解析逻辑
        │
        └─ finally:从线程本地 Set 中移除资源,清理现场

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 文档对象准备

  • doLoadDocument() 使用 DocumentLoader(默认 DefaultDocumentLoader)将 XML 转为 DOM Document
  • DocumentBuilderFactory & DocumentBuilder 设置验证、命名空间和实体解析器。
  • 返回标准 DOM Document 对象,为 BeanDefinition 注册提供结构化数据。
XmlBeanDefinitionReader.doLoadBeanDefinitions(inputSource, resource)
    │
    ├─ doLoadDocument(inputSource, resource)
    │     │
    │     └─ documentLoader.loadDocument(...) ←────────────────────────────────────────────────────┐
    │           │                                                                                  │
    │           ├─ 创建 DocumentBuilderFactory(根据校验模式和命名空间)                            │
    │           │     └─ factory.setValidating(validationMode)                                     │
    │           │     └─ factory.setNamespaceAware(namespaceAware)                                 │
    │           │                                                                                  │
    │           ├─ 创建 DocumentBuilder(设置实体解析器和错误处理器)                              │
    │           │     └─ builder.setEntityResolver(entityResolver)                                 │
    │           │     └─ builder.setErrorHandler(errorHandler)                                     │
    │           │                                                                                  │
    │           └─ builder.parse(inputSource) ←─────── 解析 XML 为 Document(DOM 树) ←────────────┘
    │
    └─ (下一步详解) registerBeanDefinitions(doc, resource)   ←──── 注册 Bean 定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

至此,Spring 完成了配置文件的读取和 XML 的解析工作,获得了 DOM 结构的 Document 对象, 接下来将其交由 registerBeanDefinitions(doc, resource) 进行解析 <bean><import> 等标签,转换 BeanDefinition;

# 分配解析策略

关键点

  1. 委托模式设计
  • XmlBeanDefinitionReader 负责整体流程管理;
  • 具体的 XML <bean> 结构解析交由 DefaultBeanDefinitionDocumentReader
  • 它内部再将解析细节委托给 BeanDefinitionParserDelegate

这种设计便于扩展和维护,符合职责分离原则。

  1. Document → Spring BeanDefinition
  • Document 是标准 XML 结构的 DOM;

  • 需要用 Spring 自定义规则(比如:<bean><alias>)去解析并转为 BeanDefinition

  • 这就是 DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions() 的职责。

    1. 典型处理方式如下:
XML 标签 处理逻辑简述
<bean> 转为 BeanDefinition 对象并注册
<alias> 调用 registry.registerAlias()
<import> 加载并递归解析其他 XML 配置文件
自定义标签 走命名空间解析器如 <context:component-scan>
  1. BeanDefinition 计数机制
  • 在注册前后统计 BeanDefinition 的数量变化;
  • 便于调试和日志记录,输出“新加载了多少个 bean 定义”。
XmlBeanDefinitionReader.registerBeanDefinitions(doc, resource)
    │
    ├─ 创建 BeanDefinitionDocumentReader 实例(默认:DefaultBeanDefinitionDocumentReader)
    │
    ├─ 获取当前容器已注册的 BeanDefinition 数量(countBefore)
    │
    └─ 调用 documentReader.registerBeanDefinitions(doc, createReaderContext(resource))
          │
          └─ DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(...)
                │
                ├─ 提取 <beans> 根元素(root = doc.getDocumentElement())
                │
                └─ 调用 doRegisterBeanDefinitions(root) ←─────── 核心解析入口
                        │
                        └─ 创建 BeanDefinitionParserDelegate(解析委派器)
                        │
                        └─ (下一步详解)parseBeanDefinitions 解析 Bean 定义也就是xml标签

    ← 返回新注册的 BeanDefinition 数量 = 当前数量 - countBefore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

实际解析逻辑由 DefaultBeanDefinitionDocumentReader 实现,通过委托给BeanDefinitionParserDelegate 处理具体元素解析。

Bean 配置资源的载入解析分为以下两个过程:

首先通过调用XML解析器将Bean配置信息转换得到Document对象, 但是这些Document并没有按照 Spring 的Bean 规则进行解析。这一步是载入的过程

其次,在完成通用的XML 解析之后,按照 Spring Bean 的定义规则对 Document 对象进行解析,其 解析过程是在接口 BeanDefinition DocumentReader DefaultBeanDefinitionDocumentReader 中实现.

# 解析xml对应的标签

关键点

  • parseBeanDefinitions
    • 入口,判断是否默认命名空间
    • 默认命名空间时,遍历子元素并调用parseDefaultElement
    • 非默认命名空间时,调用parseCustomElement
  • parseDefaultElement
    • 根据标签名分发到具体处理逻辑:
      • <import> → 加载其它配置资源
      • <alias> → 注册别名
      • <bean> → 解析Bean定义并注册
      • <beans> → 递归解析内部beans
  • parseCustomElement
    • 交给对应命名空间的NamespaceHandler处理
    • 处理自定义标签,生成BeanDefinition
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
    │
    ├─ 判断 root 是否默认命名空间(delegate.isDefaultNamespace(root))
    │
    ├─ 是默认命名空间:
    │     │
    │     ├─ 遍历 root 子元素,依次处理每个 XML 标签
    │     │     │
    │     │     ├─ 对每个子元素 ele 调用 parseDefaultElement(ele, delegate)
    │     │     │
    │     │     │   parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
    │     │     │       │
    │     │     │       ├─ 判断 ele 节点名称
    │     │     │       │     │
    │     │     │       │     ├─ 如果标签是 <import> → importBeanDefinitionResource(ele)
    │     │     │       │     │        ├─ 读取 resource 属性,解析路径
    │     │     │       │     │        ├─ 加载对应的外部 XML 资源
    │     │     │       │     │        ├─ 递归调用 registerBeanDefinitions 加载新资源
    │     │     │       │     │        └─ 合并 BeanDefinitions,发布 Import 事件
    │     │     │       │     │
    │     │     │       │     ├─ 如果标签是 <alias> → processAliasRegistration(ele)
    │     │     │       │     │        ├─ 读取 name 和 alias
    │     │     │       │     │        ├─ 校验并注册别名到容器
    │     │     │       │     │        └─ 发布 Alias 注册事件
    │     │     │       │     │
    │     │     │       │     ├─ 如果标签是 <bean> → processBeanDefinition(ele, delegate)
    │     │     │       │     │        ├─ 解析 id、class、scope 等属性,生成 BeanDefinition
    │     │     │       │     │        ├─ 解析 constructor-arg、property 等子元素
    │     │     │       │     │        ├─ 注册 BeanDefinition 到容器
    │     │     │       │     │        ├─ 处理别名,发布注册事件
    │     │     │       │     │        └─ 触发后置处理器和扩展点
    │     │     │       │     │
    │     │     │       │     └─ 如果标签是 <beans> → (下一步详解)递归调用 doRegisterBeanDefinitions(ele)
    │     │     │       │
    │     │     │       └─ 返回处理结果
    │     │     │
    │     │     └─ 继续处理下一个子节点
    │     │
    │     └─ 遍历结束,完成所有默认命名空间标签处理
    │
    └─ 否(自定义命名空间):
          │
          └─ 调用 delegate.parseCustomElement(root)
                │
                ├─ 根据自定义标签的 namespace 和 localName,选择对应的 NamespaceHandler
                │
                ├─ 交由 NamespaceHandler 解析
                │
                ├─ 生成对应的 BeanDefinition
                │
                ├─ 注册到容器
                │
                └─ 发布事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# BeanDefinition注册

解析完成后, 开始进行BeanDefinition注册

processBeanDefinition()
    │
    └─ 调用 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry)
          │
          ├─ 获取 beanName 和 BeanDefinition
          │
          ├─ 调用 registry.registerBeanDefinition(beanName, beanDefinition)
          │     │
          │     ├─ 参数校验(beanName 非空,beanDefinition 非 null)
          │     │
          │     ├─ 如果是 AbstractBeanDefinition 类型,调用 validate() 进行合法性校验
          │     │     └─ 校验失败抛出 BeanDefinitionStoreException
          │     │
          │     ├─ 查询已有的 BeanDefinition (existingDefinition = beanDefinitionMap.get(beanName))
          │     │
          │     ├─ 判断是否已有同名 BeanDefinition
          │     │     ├─ 如果存在
          │     │     │     ├─ 判断是否允许覆盖
          │     │     │     │     ├─ 不允许覆盖,抛出 BeanDefinitionOverrideException
          │     │     │     │     ├─ 允许覆盖且新定义权限更高,打印 info 日志
          │     │     │     │     ├─ 允许覆盖且新旧定义不等,打印 debug 日志
          │     │     │     │     └─ 允许覆盖且新旧定义相等,打印 trace 日志
          │     │     │     └─ 使用新的 BeanDefinition 覆盖旧的
          │     │     │
          │     │     └─ 结束
          │     │
          │     └─ 如果不存在同名 BeanDefinition
          │           ├─ 判断容器是否启动
          │           │     ├─ 启动后,加锁更新 beanDefinitionMap 和 beanDefinitionNames
          │           │     └─ 未启动,直接更新数据结构
          │           ├─ 移除手动注册的单例名称(防止冲突)
          │           └─ 清空冻结的 BeanDefinition 名称缓存
          │
          ├─ 注册完成后
          │     ├─ 若覆盖了已有 BeanDefinition 或同名单例存在,调用 resetBeanDefinition(beanName) 重置缓存
          │     ├─ 否则,若配置冻结,则清理类型缓存 clearByTypeCache()
          │     └─ 结束
          │
          ├─ 返回,注册完成
          │
          └─ BeanDefinitionReaderUtils.registerBeanDefinition 完成所有别名的注册
                ├─ 遍历别名数组 aliases
                └─ 依次调用 registry.registerAlias(beanName, alias)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

至此,Bean 配置信息中配置的 Bean 被解析过后,已经注册到IOC 容器中,被容器管理起来,真正完 成了IOC 容器初始化。


# 3. prepareBeanFactory

prepareBeanFactory(beanFactory)
    │
    ├─ 设置类加载器(BeanClassLoader)
    │
    ├─ 设置表达式解析器(SpEL → StandardBeanExpressionResolver)
    │
    ├─ 注册属性编辑器(ResourceEditorRegistrar)
    │
    ├─ 添加 ApplicationContextAwareProcessor
    │     └─ 回调 Bean 的 *Aware 接口方法
    │
    ├─ 忽略部分 Aware 接口的普通依赖注入
    │     ├─ EnvironmentAware
    │     ├─ ResourceLoaderAware
    │     ├─ ApplicationEventPublisherAware
    │     ├─ MessageSourceAware
    │     └─ ApplicationContextAware
    │
    ├─ 注册可解析依赖(ResolvableDependency)
    │     ├─ BeanFactory → 当前 BeanFactory
    │     ├─ ResourceLoader → ApplicationContext
    │     ├─ ApplicationEventPublisher → ApplicationContext
    │     └─ ApplicationContext → 当前 ApplicationContext
    │
    ├─ 添加 ApplicationListenerDetector
    │     └─ 自动识别并注册 ApplicationListener
    │
    └─ 注册内置 Bean
          ├─ environment
          ├─ systemProperties
          └─ systemEnvironment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

需要关注 Aware 接口(如 BeanNameAwareApplicationContextAwareEnvironmentAware):

  • Bean 初始化阶段,容器会回调这些接口的方法。
  • 作用是 为 Bean 注入运行所需的基础设施对象,使 Bean 能够获取自身依赖的环境或容器资源。

# 4. postProcessBeanFactory

AbstractApplicationContext 中是 空方法,专门留给子类扩展,是 容器级别的扩展点

  • 作用:提供一个 修改 BeanFactory 配置 的机会
  • 时机:
    • BeanDefinition 已经加载完成obtainFreshBeanFactory()loadBeanDefinitions() 之后)
    • Bean 还未实例化
  • 可以在此做的操作:
    1. 注册额外的 BeanPostProcessor
    2. 修改某些 BeanDefinition 的元信息(scope、lazy-init、属性值等)
    3. 增加特殊的依赖解析规则或容器级别功能

# 5. invokeBeanFactoryPostProcessors

提供给开发者的扩展点,可用于 注册或修改 BeanDefinition。BFPP在这一步进行注册, 注册后直接循环调用。

Bean 的 动态装配也是在这一步实现 (@Import / BeanDefinitionRegistry)

invokeBeanFactoryPostProcessors(beanFactory)
    │
    ├─ 如果 beanFactory 是 BeanDefinitionRegistry 类型
    │     │
    │     ├─ 将传入的 BeanFactoryPostProcessor 拆分
    │     │     ├─ BeanDefinitionRegistryPostProcessor → 可以注册/修改 BeanDefinition
    │     │     └─ 普通 BeanFactoryPostProcessor → 后处理 BeanDefinition 元信息
    │     │
    │     ├─ 处理 BeanDefinitionRegistryPostProcessor(PriorityOrdered)
    │     │     ├─ 获取容器中所有 PriorityOrdered 类型
    │     │     ├─ 排序
    │     │     └─ 调用 postProcessBeanDefinitionRegistry()
    │     │
    │     ├─ 处理 BeanDefinitionRegistryPostProcessor(Ordered)
    │     │     ├─ 获取 Ordered 类型
    │     │     ├─ 排序
    │     │     └─ 调用 postProcessBeanDefinitionRegistry()
    │     │
    │     ├─ 处理剩余未分类的 BeanDefinitionRegistryPostProcessor
    │     │     ├─ 循环获取未处理的 BeanDefinitionRegistryPostProcessor
    │     │     ├─ 排序
    │     │     └─ 调用 postProcessBeanDefinitionRegistry()
    │     │
    │     └─ 调用所有 BeanDefinitionRegistryPostProcessor 的 postProcessBeanFactory()
    │
    ├─ 调用普通 BeanFactoryPostProcessor 的 postProcessBeanFactory()
    │
    └─ 处理容器中注册的所有 BeanFactoryPostProcessor
          │
          ├─ 分类为三类
          │     ├─ PriorityOrdered 类型
          │     ├─ Ordered 类型
          │     └─ 非排序类型
          │
          ├─ 按顺序依次调用 postProcessBeanFactory()
          │     ├─ PriorityOrdered → 排序 → 调用
          │     ├─ Ordered → 排序 → 调用
          │     └─ 非排序 → 调用
          │
          └─ 清理 BeanFactory 元数据缓存(clearMetadataCache)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  1. 分两类处理
    • BeanDefinitionRegistryPostProcessor → 可以注册/修改 BeanDefinition
    • 普通 BeanFactoryPostProcessor → 只修改 BeanDefinition 元信息
  2. 三类排序优先级:PriorityOrdered → Ordered → 非排序
  3. 循环检查:保证动态注册的 BeanDefinitionRegistryPostProcessor 也能执行
  4. 最后清理缓存:确保元数据与 BeanDefinition 保持一致

# 6. registerBeanPostProcessors

提供在 Bean 实例化前后增强 的扩展点,例如 AOP、@Autowired 等。不区分前置 或者 后置增强, 在Bean实例化阶段会遍历beanPostProcessors 列表, 通过调用postProcessBeforeInitialization或者postProcessAfterInitialization执行前置后置增强逻辑。

registerBeanPostProcessors(beanFactory, applicationContext)
    │
    ├─ 获取容器中所有 BeanPostProcessor 名称
    │
    ├─ 计算目标 BeanPostProcessor 数量
    │     └─ 添加 BeanPostProcessorChecker(检测提前创建的 Bean)
    │
    ├─ 分类 BeanPostProcessor
    │     ├─ PriorityOrdered 类型 → priorityOrderedPostProcessors
    │     │     └─ 内部增强器(MergedBeanDefinitionPostProcessor)加入 internalPostProcessors
    │     ├─ Ordered 类型 → orderedPostProcessorNames
    │     └─ 非排序类型 → nonOrderedPostProcessorNames
    │
    ├─ 注册 PriorityOrdered 类型
    │     ├─ 排序
    │     └─ 调用 registerBeanPostProcessors
    │
    ├─ 注册 Ordered 类型
    │     ├─ 获取 Bean 实例
    │     ├─ 内部增强器加入 internalPostProcessors
    │     ├─ 排序
    │     └─ 调用 registerBeanPostProcessors
    │
    ├─ 注册非排序类型
    │     ├─ 获取 Bean 实例
    │     ├─ 内部增强器加入 internalPostProcessors
    │     └─ 调用 registerBeanPostProcessors
    │
    ├─ 注册内部增强器(MergedBeanDefinitionPostProcessor)
    │     ├─ 排序
    │     └─ 调用 registerBeanPostProcessors
    │
    └─ 注册 ApplicationListenerDetector
          └─ 自动识别并注册 ApplicationListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  1. 分类注册:PriorityOrdered → Ordered → 非排序 → 内部增强器
  2. 内部增强器:通常涉及 AOP、@Autowired、@PostConstruct 等
  3. BeanPostProcessorChecker:提醒在 BeanPostProcessor 注册完成前就被实例化的 Bean
  4. ApplicationListenerDetector:自动注册事件监听器

# 7. initMessageSource

作用:为容器提供统一的消息解析机制(Internationalization, i18n),允许 Bean 或应用根据 Locale 获取对应的文本、提示信息、异常消息等。

initMessageSource(applicationContext)
│
├─ 1. 检查 BeanFactory 中是否已经注册了 MessageSource
│     ├─ 如果有,直接使用该 MessageSource Bean
│     └─ 如果没有,创建默认的 DelegatingMessageSource
│
├─ 2. 配置 MessageSource
│     ├─ 父级 MessageSource(如果存在父上下文,则可以级联查询消息)
│     ├─ 缓存属性和资源文件路径
│     └─ 设置默认文本处理策略(如找不到 key 时返回 key 本身)
│
└─ 3. 将 MessageSource 设置到 ApplicationContext
      └─ 通过 getMessage() / getMessageSourceResolvable() 提供统一调用接口
1
2
3
4
5
6
7
8
9
10
11
12
13
  1. 统一消息访问接口
    • 所有 Bean 或应用可以通过 applicationContext.getMessage(...) 获取消息
    • 支持多语言(Locale),可根据用户或系统环境动态解析消息文本
  2. 父子容器支持
    • 如果父上下文存在 MessageSource,当前上下文会级联查询父上下文
    • 保证不同模块或子容器可以共享消息资源
  3. 默认实现
    • DelegatingMessageSource:默认消息源,通常查找 ResourceBundleMessageSourceReloadableResourceBundleMessageSource
    • 如果没有自定义 MessageSource,容器会自动创建默认实现,保证消息解析不为空
  4. 热加载与刷新
    • 如果使用 ReloadableResourceBundleMessageSource,可以在运行时刷新消息资源
    • 配合 ContextRefreshedEvent 可以实现消息或配置的热加载
  5. 使用场景
    • 国际化文本显示(如 UI 文本、提示信息)
    • 异常消息国际化
    • 自定义 Bean 内部提示或日志多语言

# 8. initApplicationEventMulticaster

该方法用于 初始化 Spring 的事件广播器(ApplicationEventMulticaster),是 Spring 事件驱动机制的核心步骤。

  1. 作用

    • 创建/获取广播器:为容器准备 ApplicationEventMulticaster,用于事件分发。

    • 维护监听器:负责注册和管理所有的 ApplicationListener

    • 事件分发:在事件发布时,调用 multicastEvent(event) 通知合适的监听器。

  2. 执行时机

    • refresh() 流程中,在 BeanPostProcessor 注册之后、普通 Bean 实例化之前

    • 确保容器启动后,所有 ApplicationListener 已注册到广播器中。

  3. 核心逻辑

    • 检查用户是否自定义 ApplicationEventMulticaster Bean

      • 如果有 → 使用用户自定义实现。

      • 如果没有 → 创建默认 SimpleApplicationEventMulticaster 并注册到容器。

    • 遍历所有 ApplicationListener Bean,调用 addApplicationListener() 注册到广播器。

  4. 事件驱动机制(观察者模式)

    Spring 的事件驱动设计遵循 典型的观察者模式(Observer Pattern)

    1. 事件发布方(Publisher)
      • 调用 ApplicationEventPublisher.publishEvent(event) → 委托给广播器。
    2. 事件广播器(Multicaster)
      • 保存监听器集合 → 遍历并调用匹配监听器的 onApplicationEvent(event)
    3. 事件监听器(Listener)
      • 通过实现 ApplicationListener<E>@EventListener 处理特定事件。
  5. 性能优化

    • 早期 Spring:广播器向 所有监听器 分发事件,监听器内部再做类型判断。
    • Spring 4.2+:广播器在分发时会筛选,只通知对当前事件类型感兴趣的监听器,避免无效回调,提高性能。

其实并没有这么高大上, 本质上你发布的Spring事件会委托给广播器, 广播器持有所有监听器的引用, 循环匹配罢了, 大致示例如下

// 1. 业务代码:发布事件
public void doSomething() {
    ApplicationEvent event = new MyEvent(this);
    applicationContext.publishEvent(event);  // 发布事件
}

// 2. ApplicationContext 发布事件(和同步一样)
public void publishEvent(ApplicationEvent event) {
    this.applicationEventMulticaster.multicastEvent(event);
}

// 3. 广播器:区分同步/异步监听器
public void multicastEvent(ApplicationEvent event) {
    List<ApplicationListener> listeners = getApplicationListeners(event);

    for (ApplicationListener listener : listeners) {
        if (isAsyncListener(listener)) {
            // 异步监听器:提交到线程池
            taskExecutor.submit(() -> listener.onApplicationEvent(event));
        } else {
            // 同步监听器:直接调用
            listener.onApplicationEvent(event);
        }
    }
}

// 4. 普通监听器
@Component
public class MySyncListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("【同步】监听到事件: " + event);
    }
}

// 5. 异步监听器(用 @Async 标记)
@Component
public class MyAsyncListener implements ApplicationListener<MyEvent> {
    @Async
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("【异步】监听到事件: " + event);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 9. onRefresh

作用:在容器刷新过程中留给子类扩展的钩子方法,用于执行子类特定的初始化逻辑。

onRefresh(applicationContext)
│
├─ 1. 子类可覆盖该方法,实现自定义初始化逻辑
│     ├─ WebApplicationContext:初始化 DispatcherServlet、HandlerMapping、HandlerAdapter 等 MVC 组件
│     ├─ 自定义上下文:可以初始化特定资源或组件
│
├─ 2. 执行前提
│     ├─ BeanFactory 已完成标准单例 Bean 的初始化
│     ├─ ApplicationEventMulticaster 已经可用(但监听器可能尚未注册完全)
│
└─ 3. 常见用途
      ├─ 初始化框架特定 Bean(如 MVC 组件、消息队列监听器)
      ├─ 配置扩展 Bean 或插件
      └─ 启动某些资源或服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 10. registerListeners

作用:将容器中所有 ApplicationListener 注册到 ApplicationEventMulticaster(事件传播器)中,以便发布事件时可以正确触发监听器。

registerListeners(beanFactory, applicationContext)
│
├─ 1. 获取容器中所有 ApplicationListener Bean
│     ├─ 直接实现 ApplicationListener 的 Bean
│     └─ 通过 SmartInitializingSingleton 或其它注册方式添加的监听器
│
├─ 2. 将监听器注册到 ApplicationEventMulticaster
│     └─ multicaster.addApplicationListener(listener)
│
├─ 3. 处理 ApplicationListener 的顺序
│     ├─ 支持 PriorityOrdered / Ordered 接口排序
│     └─ 未排序的放到默认顺序
│
└─ 4. 支持早期事件监听(earlyEvents)
      └─ 在容器刷新前发布的事件会缓存在 earlyEvents 中,注册完成后重新广播
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. 为什么在 onRefresh 之后?
    • 子容器可能有自己的 ApplicationListener
    • 父子容器的刷新顺序:先刷新父容器 → 父容器事件发布 → 再刷新子容器 → 子容器事件发布
    • registerListeners 放在 onRefresh 之后,可以确保所有父子容器的监听器都已注册完成,避免漏掉子容器监听器
  2. 与 finishRefresh 的关系
    • finishRefresh 会调用 ContextRefreshedEvent 的广播
    • 如果监听器未注册,就会错过这个事件
    • 所以必须先注册监听器,再发布刷新事件
  3. 早期事件(earlyEvents)处理
    • 在某些情况下,Bean 初始化过程中可能触发事件
    • 这些事件会先被缓存(earlyEvents),等监听器注册完成后再统一广播
    • 避免事件丢失
  4. 排序规则
    • 支持 PriorityOrdered > Ordered > 默认顺序
    • 保证关键监听器先执行(如配置刷新、缓存加载、AOP 初始化等)

# 11. finishBeanFactoryInitialization

**重点:**所有非懒加载单例 Bean 都会在该方法中被初始化实例化,也就是说之前注册的 BeanDefinition 会被实例化,同时所有增强方法(BPP、MBDPP、Aware 回调等)也会在这里触发。

finishBeanFactoryInitialization(beanFactory)
│
├─ 1. 初始化 ConversionService
├─ 2. 注册默认的 StringValueResolver(占位符解析)
├─ 3. 初始化 LoadTimeWeaverAware Bean
├─ 4. 清除临时 ClassLoader
├─ 5. 冻结 BeanDefinition 配置
│
└─ 6. 实例化剩余的单例 Bean(preInstantiateSingletons)
      │
      ├─ 遍历所有非抽象、非懒加载、单例 BeanDefinition
      │     └─ 对 FactoryBean 特殊处理(&FactoryBeanName 才能获取工厂本身)
      │
      └─ 调用 getBean(beanName) → doGetBean
            │
            ├─ ① 名称转换(别名解析、FactoryBean 处理)
            │
            ├─ ② getSingleton(beanName, allowEarlyReference) → 三级缓存机制
            │     ├─ 一级缓存 singletonObjects(完全初始化单例)
            │     ├─ 二级缓存 earlySingletonObjects(提前暴露半成品)
            │     └─ 三级缓存 singletonFactories(ObjectFactory,延迟生成早期引用,支持 AOP)
            │
            ├─ ③ 如果缓存未命中 → createBean(beanName, mbd, args) → doCreateBean
            │     │
            │     createBean(beanName, mbd, args)
            │     │
            │     ├─ ① 实例化 Bean(createBeanInstance)
            │     │     └─ 构造方法 / 工厂方法 / Supplier
            │     │
            │     ├─ ② MergedBeanDefinitionPostProcessor
            │     │     └─ postProcessMergedBeanDefinition()
            │     │         (解析 @Autowired/@Value/@Resource 等注解元数据,缓存注入点)
            │     │
            │     ├─ ③ 提前暴露单例(循环依赖处理)
            │     │     └─ addSingletonFactory(beanName, ObjectFactory)
            │     │         ├─ 三级缓存 singletonFactories:存 ObjectFactory
            │     │         ├─ 清理二级缓存 earlySingletonObjects(保证干净状态)
            │     │         └─ 注册 beanName 到 registeredSingletons
            │     │
            │     ├─ ④ populateBean(依赖注入)
            │     │     ├─ 遍历 Bean 属性
            │     │     │     ├─ 普通属性注入(通过 BeanDefinition)
            │     │     │     ├─ @Autowired / @Resource / @Value 注解依赖
            │     │     │     │     └─ 调用 getBean(依赖Bean)
            │     │     │     │         ├─ 依赖 Bean 已在一级缓存 → 直接返回
            │     │     │     │         ├─ 依赖 Bean 正在创建 → 从三级缓存 / earlySingletonObjects 获取半成品
            │     │     │     │         └─ 依赖 Bean 未创建 → 递归 createBean
            │     │     └─ 注入完成 → Bean 属性已填充
            │     │
            │     ├─ ⑤ initializeBean(初始化)
            │     │     ├─ Aware 接口回调(BeanNameAware、BeanFactoryAware 等)
            │     │     ├─ BeanPostProcessor.postProcessBeforeInitialization()
            │     │     ├─ init-method / @PostConstruct
            │     │     └─ BeanPostProcessor.postProcessAfterInitialization()
            │     │         (典型:AOP 代理生成)
            │     │
            │     ├─ ⑥ 缓存升级(三级 → 二级 → 一级)
            │     │     ├─ 调用 getEarlyBeanReference(beanName) → 获取可能的代理对象
            │     │     ├─ 放入二级缓存 earlySingletonObjects(半成品或代理)
            │     │     ├─ 放入一级缓存 singletonObjects(完全初始化 Bean)
            │     │     ├─ 清理二级缓存 earlySingletonObjects
            │     │     └─ 清理三级缓存 singletonFactories
            │     │
            │     └─ ⑦ 注册 DisposableBean(销毁回调)
            │
            └─ ④ 返回 Bean(可能来自缓存,也可能是新创建的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  1. MergedBeanDefinitionPostProcessor
    • BeanPostProcessor 的子类
    • 在 createBean 阶段提前执行,用于解析注解元数据(@Autowired / @Value / @Resource)并缓存注入点信息
    • 作用:为 populateBean 时的依赖注入做准备
  2. populateBean
    • 真正发生依赖注入的阶段
    • 注入顺序遵循 BeanDefinition 配置和注解
    • 循环依赖时,会从三级缓存 / 二级缓存获取半成品 Bean 注入
  3. BeanPostProcessor
    • 初始化前后触发:postProcessBeforeInitializationpostProcessAfterInitialization
    • AOP 代理典型在 postProcessAfterInitialization 时生成
    • initializeBean 阶段还会调用 Aware 回调和 init-method/@PostConstruct
  4. 循环依赖解决流程(以 A ↔ B 为例)
@Component
class A {
    @Autowired
    private B b;
}

@Component
class B {
    @Autowired
    private A a;
}
1
2
3
4
5
6
7
8
9
10
11
  • 流程:
    1. 容器开始创建 A → 实例化 A → 放入三级缓存 singletonFactories
    2. populateBean(A) → 发现需要 B → 调用 getBean(B)
    3. 容器创建 B → 实例化 B → 放入三级缓存 singletonFactories
    4. populateBean(B) → 发现需要 A → getBean(A)
    5. A 正在创建 → 从三级缓存拿到 A 的早期引用 → 放入二级缓存
    6. B 注入 A 的早期引用 → 初始化 B → 放入一级缓存
    7. 回到 A → 注入 B → 初始化 A → 放入一级缓存
  • 注意:
    • 早期引用(early reference)可能是代理对象
    • 循环依赖只针对 单例 Bean 支持
    • FactoryBean 需特殊处理:&FactoryBeanName 获取工厂本身,否则返回 FactoryBean 产物
  1. 缓存升级顺序
    • 三级缓存(ObjectFactory) → 二级缓存(earlySingletonObjects) → 一级缓存(singletonObjects)
    • 保证:
      1. 循环依赖期间可以注入半成品或代理
      2. 完整 Bean 最终存入一级缓存,二三级缓存清理
      3. 避免重复创建或覆盖 Bean
  2. DisposableBean 注册
    • 初始化完成后,单例 Bean 会注册销毁回调
    • 作用:容器关闭时自动调用 destroy 方法

# 12. finishRefresh

作用:完成 Spring 容器刷新流程,发布 ContextRefreshedEvent,可用于触发依赖容器初始化完成后的事件监听、数据热加载、定时任务启动等。

finishRefresh(applicationContext)
│
├─ 1. 初始化 LifecycleProcessor(生命周期处理器)
│     └─ 管理容器中的 Lifecycle Bean(如 SmartLifecycle),确保启动顺序和依赖
│
├─ 2. 调用 LifecycleProcessor.onRefresh()
│     └─ 启动所有生命周期 Bean(SmartLifecycle 自动按 phase 启动)
│
├─ 3. 发布 ContextRefreshedEvent
│     ├─ 所有注册的 ApplicationListener 会收到事件通知
│     ├─ 可用于:
│     │     ├─ 热加载配置或数据
│     │     ├─ 启动定时任务或消息监听器
│     │     └─ 触发依赖容器完成初始化的自定义逻辑
│
├─ 4. 发布其他事件(可选)
│     └─ ApplicationEventMulticaster 会将事件广播给所有监听器
│
└─ 5. 完成容器刷新
      └─ 此时容器中所有非懒加载单例 Bean 已完成实例化、初始化、依赖注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  1. ContextRefreshedEvent
    • 事件发布时,容器已经完成:
      • Bean 的实例化与初始化
      • 循环依赖解决
      • BeanPostProcessor 和 AOP 代理生效
    • 避免在监听器中再去修改 Bean 定义或创建新的单例 Bean(容易引发异常)
  2. LifecycleProcessor
    • 管理 SmartLifecycle Bean 的自动启动
    • 确保按 phase 顺序启动
    • 容器刷新后生命周期 Bean 已处于运行状态
  3. 热加载处理
    • 数据或配置热加载逻辑可以放在 ApplicationListener<ContextRefreshedEvent>
    • 可以保证 Bean 已经完全可用,避免空指针或循环依赖问题
  4. 异常防护
    • finishRefresh 在发布事件前会捕获异常,防止整个刷新流程中断
    • 事件监听中出现异常不会影响其他 Bean 的初始化

# Spring 常见问题整理

# 1. Spring 的核心扩展点

Spring 提供了多种扩展点,用于在 Bean 创建和容器初始化阶段增强功能:

扩展点 作用对象 触发时机 典型用途 备注
BeanFactoryPostProcessor (BFPP) BeanDefinition Bean 实例化前 修改 BeanDefinition 元信息、注册额外 Bean 工厂级扩展,不依赖 Bean 实例
MergedBeanDefinitionPostProcessor (BMPP) Bean + BeanDefinition Bean 实例化后、初始化前 解析注解(如 @Autowired/@Value)、缓存依赖元数据 BPP 的子类,为 populateBean 提供元数据支持
BeanPostProcessor (BPP) Bean 实例 初始化前后 依赖注入、AOP 代理、初始化逻辑增强 包含 postProcessBeforeInitializationpostProcessAfterInitialization
普通 Bean Bean 实例 容器初始化阶段 应用逻辑 可被 BFPP/BMPP/BPP 增强

⚠️ 特殊 Bean(如 BPP/BFPP)不一定会立即实例化,它们主要提供 增强逻辑


# 2. 扩展点触发顺序

  1. BFPP 阶段

    • 容器完成 BeanDefinition 加载
    • 执行所有 BeanFactoryPostProcessor
    • 修改 BeanDefinition 或注册额外 Bean
  2. 注册 BPP

    • 调用 registerBeanPostProcessors
    • 所有 BeanPostProcessor 被提前注册到容器中
    • 包含 BMPP 的实现(如 AutowiredAnnotationBeanPostProcessor
  3. BMPP 阶段

    • postProcessMergedBeanDefinition 被调用
    • Bean 实例已创建,但属性尚未注入
    • 缓存注解元数据,为依赖注入和 AOP 提供信息
  4. 普通 Bean 实例化

    • 调用 createBean / doCreateBean
    • instantiateBean → 构造方法 / 工厂方法
    • 提前暴露单例,支持循环依赖
  5. populateBean

    • 依赖注入
    • 对注解依赖(@Autowired、@Value、@Resource)进行注入
    • 循环依赖通过三级缓存解决
  6. initializeBean

    • 调用 Aware 接口回调
    • BPP 的 postProcessBeforeInitialization
    • init-method / @PostConstruct
    • BPP 的 postProcessAfterInitialization(典型:AOP 代理生成)

    需要注意 具体哪个bean调用哪个BPP是由BPP的具体实现决定的

  7. 缓存升级

    • 三级缓存(ObjectFactory) → 二级缓存(earlySingletonObjects) → 一级缓存(singletonObjects)
    • Bean 完全初始化后正式放入一级缓存
  8. 注册 DisposableBean

    • 销毁回调注册

# 3. 循环依赖处理示意

@Component
class A {
    @Autowired
    private B b;
}

@Component
class B {
    @Autowired
    private A a;
}
1
2
3
4
5
6
7
8
9
10
11
  • 容器创建 A → 实例化 A → 放入三级缓存(ObjectFactory)
  • A 依赖 B → getBean(B) → 实例化 B → 放入三级缓存
  • B 依赖 A → getBean(A) → 从三级缓存获取早期引用
  • 完成 B 的 populateBean 和初始化 → 放入一级缓存
  • 回到 A → 注入 B → 初始化 → 放入一级缓存

🔑 关键点:

  • 提前暴露 Bean 用于解决循环依赖
  • BMPP 在 populateBean 之前生效,为依赖注入提供元数据
  • BPP 在 initializeBean 阶段生效,AOP 代理生成于 postProcessAfterInitialization

# 4. 注意事项

  1. BPP 与 BMPP 的提前注册
    • 必须在普通 Bean 实例化前注册,否则依赖注入、AOP 无法生效
  2. 循环依赖
    • 仅支持 单例 Bean 的循环依赖
    • 原型 Bean 循环依赖会抛出异常
  3. 早期引用
    • 对象在三级缓存中可能是“半成品”
    • postProcessAfterInitialization 可替换为代理对象
  4. BeanFactoryPostProcessor 的限制
    • 只能操作 BeanDefinition 元数据
    • 不可操作尚未注册的 Bean 或 Bean 实例
  5. BMPP 解析元数据
    • 缓存依赖信息,保证 populateBean 时可以正确注入
    • 解析注解(@Autowired/@Value/@Resource)
  6. 父子容器与事件监听
    • registerListeners 必须在 finishBeanFactoryInitialization / onRefresh 之后
    • 确保父子容器的监听器都能收到 ContextRefreshedEvent
  7. Lifecycle 与初始化顺序
    • SmartLifecycle Bean 按 phase 启动
    • finishRefresh 阶段发布事件,保证 Bean 完全可用

# 5. 总结

  • BFPP:修改 BeanDefinition
  • BMPP:Bean 实例化后、初始化前,解析元数据、缓存依赖信息
  • BPP:Bean 初始化前后增强(依赖注入、AOP、init 方法)
  • 普通 Bean:被容器创建和初始化
  • 循环依赖、缓存升级、初始化顺序 是理解 Spring 容器的核心

理解这三类扩展点的触发顺序和作用对象,是分析 Spring IOC 行为、调试依赖注入、AOP 和循环依赖问题的关键。