Spring Framework 7.0.9 深度剖析-08-扩展点体系:后处理器与注册机制

4 阅读27分钟

Spring Framework 7.0.9 深度剖析-08-扩展点体系:后处理器与注册机制

1. 本章导读

Spring 容器之所以成为一个"可扩展"的容器,而不是一个写死的 IoC 黑盒,靠的不是某个宏大的设计模式,而是一整套刻意留给用户去实现的接口。这些接口散布在 spring-beans 与 spring-context 两个模块里,名字相似(BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor),但它们被调用的时机、能拿到的对象、能修改的东西、执行顺序,全部由容器在 refresh() 的固定位置硬编码驱动。本章的目标,就是把这套扩展点体系在 Spring Framework 7.0.9 源码里的真实调用位置、排序规则、数据结构和典型实现一次讲透。

读完本章你应该能回答以下问题:

  • 为什么 BeanDefinitionRegistryPostProcessor 一定先于 BeanFactoryPostProcessor 执行?这个先后顺序在 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 里是靠几段循环、几个 Set、几次 getBean() 硬保证出来的?
  • BeanPostProcessor 与 BeanFactoryPostProcessor 名字只差一个单词,为什么前者作用于"bean 实例"、后者作用于"BeanDefinition"?它们分别在 refresh() 的哪一步被实例化、被调用?
  • Aware 家族里,BeanNameAware/BeanClassLoaderAware/BeanFactoryAware 是在 AbstractAutowireCapableBeanFactory.invokeAwareMethods 里被 inline 调用的,而 ApplicationContextAware/EnvironmentAware 等却是由 ApplicationContextAwareProcessor 这个 BeanPostProcessor 在 postProcessBeforeInitialization 阶段回调的——为什么要分成两路?这两路的先后关系是什么?
  • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 一旦返回非 null,为什么后续的 populateBean、initializeBean 全被跳过?这个短路在 AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation 里是怎么写的?
  • MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition 是 @Autowired/@Value 注解元数据收集的挂载点,它在 doCreateBean 的什么时机被触发?为什么必须放在"实例化完成之后、属性填充之前"?
  • FactoryBean.getObject() 产生的单例对象,为什么还要再过一遍 postProcessObjectFromFactoryBean?这个后处理与 AOP 自动代理是什么关系?
  • SmartLifecycle 的 start() 顺序为什么按 getPhase() 从小到大、stop() 从大到小?DefaultLifecycleProcessor 是怎么用 TreeMap<Integer, LifecycleGroup> 实现这个分组的?

本章涉及的核心模块是 spring-beans(容器底层 SPI)与 spring-context(应用上下文层面的扩展点编排)。前置知识是你已经知道 AbstractApplicationContext.refresh() 的十二步骨架(prepareRefresh → obtainFreshBeanFactory → prepareBeanFactory → postProcessBeanFactory → invokeBeanFactoryPostProcessors → registerBeanPostProcessors → initMessageSource → initApplicationEventMulticaster → onRefresh → registerListeners → finishBeanFactoryInitialization → finishRefresh),本章不再重复讲 refresh 整体流程,而是把"扩展点在这十二步里的精确位置"作为主线。

源码版本:gradle.properties 中 version=7.0.9;所有路径均为仓库相对路径,如无特别说明,仓库根目录为 spring-framework-7.0.9。


2. 核心概念:扩展点全景图

2.1 什么是"扩展点"

Spring 源码里并没有一个叫 ExtensionPoint 的标记接口。所谓扩展点,是容器在生命周期的固定位置主动回调的一组接口。它们的共同特征是:

  1. 接口本身极简(通常只有 1~3 个方法),方法签名里只出现容器自己的类型(ConfigurableListableBeanFactory、RootBeanDefinition、Object bean, String beanName);
  2. 实现类由用户提供,但实例化时机由容器硬编码,不由用户决定;
  3. 多个扩展点同时存在时,容器按 PriorityOrdered → Ordered → 无序 的固定三批顺序执行;
  4. 扩展点自身也是一个 bean,因此它也能被容器依赖注入、也能被别的 BeanPostProcessor 处理——这既是它的能力,也是它的坑(后文"常见问题"会讲)。

按照"作用对象"与"作用时机"两个维度,可以把 Spring 7.0.9 留给用户的扩展点分成三大族。

2.2 容器级扩展点(作用于 BeanDefinition,发生在任何 bean 实例化之前)

这一族扩展点的共同特点是:它被调用时,容器里一个普通单例 bean 都还没被创建,用户拿到的是 BeanFactory 或 BeanDefinitionRegistry,能改的是"蓝图"(BeanDefinition),不能改"成品"(bean 实例)。

扩展点接口所在模块与路径调用时机能做什么
BeanFactoryPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/BeanFactoryPostProcessor.javaAbstractApplicationContext.invokeBeanFactoryPostProcessors 中,所有单例实例化之前修改已加载的 BeanDefinition 的属性值(如占位符替换、属性覆盖)
BeanDefinitionRegistryPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.java先于所有 BeanFactoryPostProcessor,在 registry 阶段向注册表新增 BeanDefinition(如 ConfigurationClassPostProcessor 扫描 @Component、@Bean)
ImportSelectorspring-context/src/main/java/org/springframework/context/annotation/ImportSelector.java@Configuration 类解析阶段(由 ConfigurationClassPostProcessor 驱动)根据 @Import 的注解元数据返回要导入的配置类全限定名数组
DeferredImportSelectorspring-context/src/main/java/org/springframework/context/annotation/DeferredImportSelector.java所有普通 @Configuration 处理完之后才执行同上,但延迟到最后,配合 Group 跨选择器排序
ImportBeanDefinitionRegistrarspring-context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java@Configuration 类解析阶段拿到 BeanDefinitionRegistry 直接 registerBeanDefinition,动态注册大量 bean
BeanFactoryInitializerspring-beans/src/main/java/org/springframework/beans/factory/config/BeanFactoryInitializer.javafinishBeanFactoryInitialization 中 preInstantiateSingletons 之前提前对 beanFactory 做一次性初始化(7.0 新增的轻量钩子)

2.3 Bean 级扩展点(作用于 bean 实例,发生在单个 bean 的创建过程中)

这一族扩展点在每个 bean 的创建流程里被回调,作用对象是刚 new 出来的那个对象本身。它们的调用位置集中在 AbstractAutowireCapableBeanFactory 的 createBean/doCreateBean/initializeBean/populateBean 四个方法里。

扩展点接口所在模块与路径回调方法在 doCreateBean 中的位置
BeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/BeanPostProcessor.javapostProcessBeforeInitialization / postProcessAfterInitializationinitializeBean 中,invokeInitMethods 前后
InstantiationAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.javapostProcessBeforeInstantiation / postProcessAfterInstantiation / postProcessPropertiesresolveBeforeInstantiation(短路)/ populateBean 开头与属性应用前
SmartInstantiationAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.javapredictBeanType / determineBeanType / determineCandidateConstructors / getEarlyBeanReference类型预测 / 构造器选择 / 三级缓存早期引用暴露
MergedBeanDefinitionPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.javapostProcessMergedBeanDefinitiondoCreateBean 中实例化完成后、populateBean 之前
DestructionAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.javapostProcessBeforeDestruction / requiresDestructionDisposableBeanAdapter.destroy 中
FactoryBeanspring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.javagetObject / getObjectType / isSingletonFactoryBeanRegistrySupport.getObjectFromFactoryBean
SmartFactoryBeanspring-beans/src/main/java/org/springframework/beans/factory/SmartFactoryBean.javaisEagerInit / getObject(Class)同上,扩展了按类型取对象
SmartInitializingSingletonspring-beans/src/main/java/org/springframework/beans/factory/SmartInitializingSingleton.javaafterSingletonsInstantiatedDefaultListableBeanFactory.preInstantiateSingletons 末尾

2.4 生命周期级扩展点(作用于容器整体的启停)

这一族扩展点不在单个 bean 的创建流程里,而是在容器 refresh() 的最后一步 finishRefresh 与 close() 的 doClose 里被统一回调。

扩展点接口所在模块与路径回调时机语义
Lifecyclespring-context/src/main/java/org/springframework/context/Lifecycle.javaLifecycleProcessor.start() / stop()最基础的 start()/stop()/isRunning()
Phasedspring-context/src/main/java/org/springframework/context/Phased.java同上提供 getPhase() 排序值
SmartLifecyclespring-context/src/main/java/org/springframework/context/SmartLifecycle.javaDefaultLifecycleProcessor.onRefresh() / onClose()在 Lifecycle 基础上加 isAutoStartup()/stop(Runnable)/getPhase()
InitializingBeanspring-beans/src/main/java/org/springframework/beans/factory/InitializingBean.javaAbstractAutowireCapableBeanFactory.invokeInitMethodsafterPropertiesSet(),属性填充后的初始化回调
DisposableBeanspring-beans/src/main/java/org/springframework/beans/factory/DisposableBean.javaDisposableBeanAdapter.destroydestroy(),容器关闭时的销毁回调
*Aware 家族spring-beans / spring-context 多包invokeAwareMethods / ApplicationContextAwareProcessor把容器自身的组件(BeanFactory、ApplicationContext、Environment…)注入 bean

2.5 一张图看懂扩展点在 refresh 中的位置

AbstractApplicationContext.refresh()
 ├─ prepareRefresh()
 ├─ obtainFreshBeanFactory()
 ├─ prepareBeanFactory()
 │    └─ new ApplicationContextAwareProcessor(this)  ← Aware 后处理器在此注册
 │    └─ new ApplicationListenerDetector(this)
 ├─ postProcessBeanFactory()                          ← 子类扩展点(空实现)
 ├─ invokeBeanFactoryPostProcessors()
 │    ├─ [容器级] BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()
 │    │    └─ 内部又触发 ConfigurationClassPostProcessor → @Import → ImportSelector/Registrar
 │    └─ [容器级] BeanFactoryPostProcessor.postProcessBeanFactory()
 ├─ registerBeanPostProcessors()
 │    └─ [Bean级] 把 BeanPostProcessor 实例注册进 beanFactory(三批排序)
 ├─ initMessageSource() / initApplicationEventMulticaster()
 ├─ onRefresh()                                       ← 子类扩展点(如 Web 容器)
 ├─ registerListeners()
 ├─ finishBeanFactoryInitialization()
 │    └─ preInstantiateSingletons()
 │         ├─ 每个 singleton bean: createBean → doCreateBean
 │         │    ├─ resolveBeforeInstantiation()       ← [Bean级] postProcessBeforeInstantiation 短路
 │         │    ├─ createBeanInstance()
 │         │    ├─ applyMergedBeanDefinitionPostProcessors() ← [Bean级] @Autowired 元数据收集
 │         │    ├─ addSingletonFactory()              ← 三级缓存(循环依赖)
 │         │    ├─ populateBean()
 │         │    │    ├─ postProcessAfterInstantiation()
 │         │    │    └─ postProcessProperties()       ← @Autowired/@Value 字段注入
 │         │    └─ initializeBean()
 │         │         ├─ invokeAwareMethods()           ← [Aware] BeanName/ClassLoader/BeanFactory
 │         │         ├─ applyBeanPostProcessorsBeforeInitialization() ← [Aware] ApplicationContextAwareProcessor 等
 │         │         ├─ invokeInitMethods()           ← [生命周期] InitializingBean.afterPropertiesSet
 │         │         └─ applyBeanPostProcessorsAfterInitialization() ← AOP 代理在此产生
 │         └─ 所有单例就绪后: SmartInitializingSingleton.afterSingletonsInstantiated()
 ├─ finishRefresh()
 │    └─ LifecycleProcessor.onRefresh()                ← [生命周期] SmartLifecycle.start() 按 phase 升序
 └─ close() → doClose()
      ├─ publishEvent(ContextClosedEvent)
      ├─ LifecycleProcessor.onClose()                 ← [生命周期] SmartLifecycle.stop() 按 phase 降序
      └─ destroyBeans() → destroySingletons()
           └─ DisposableBeanAdapter.destroy()        ← [Bean级] DestructionAwareBeanPostProcessor.postProcessBeforeDestruction

这张图是全章的"地图",后续每一节都是在这张图上的某个点展开源码级剖析。

3. 源码剖析(一):BeanFactoryPostProcessor 与 BeanDefinitionRegistryPostProcessor

3.1 两个接口的定义:一个改"属性",一个加"bean"

先看最基础的 BeanFactoryPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/config/BeanFactoryPostProcessor.java,第 69-82 行):

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

注意 javadoc 里那句关键的话:"All bean definitions will have been loaded, but no beans will have been instantiated yet." 这就是这个扩展点的全部语义边界——它能拿到 ConfigurableListableBeanFactory,通过 getBeanDefinition(name) 拿到每一个 BeanDefinition 并修改其 propertyValues、scope、lazyInit 等元数据,但它绝对不应该去 beanFactory.getBean(name) 触发实例化,因为那样会破坏容器"先全部改完蓝图、再统一创建实例"的两阶段契约。接口注释里也明确警告:"A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side effects."

再看 BeanDefinitionRegistryPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.java,第 34-56 行):

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

	/**
	 * Empty implementation of {@link BeanFactoryPostProcessor#postProcessBeanFactory}
	 * since custom {@code BeanDefinitionRegistryPostProcessor} implementations will
	 * typically only provide a {@link #postProcessBeanDefinitionRegistry} method.
	 * @since 6.1
	 */
	@Override
	default void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}

}

这里有几个 7.0.9 的细节值得点出:

  1. 它继承自 BeanFactoryPostProcessor,所以一个 BeanDefinitionRegistryPostProcessor 同时是一个 BeanFactoryPostProcessor。容器在收集"所有 BFPP"时会把它也列出来,但会通过 instanceof 把它分流到"registry 组"。
  2. postProcessBeanFactory 在 6.1 之后变成了空默认方法(第 52-54 行)。这意味着用户实现一个 registry 后处理器时,只需要重写 postProcessBeanDefinitionRegistry,不必再被迫写一个空的 postProcessBeanFactory。这是 7.0.9 与旧教程的一个差异点。
  3. 它拿到的参数是 BeanDefinitionRegistry(而不是 ConfigurableListableBeanFactory),这个接口暴露的是 registerBeanDefinition/removeBeanDefinition/containsBeanDefinition 等"注册表"操作,不暴露 getBean()。这是一种刻意的能力收窄:registry 后处理器只允许"加 bean 定义",不允许"取 bean 实例"。

框架里最重要的 BeanDefinitionRegistryPostProcessor 实现是 ConfigurationClassPostProcessor(spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java),它负责解析所有 @Configuration 类、扫描 @ComponentScan、处理 @Import、注册 @Bean 方法对应的 BeanDefinition。它是整个注解驱动容器的"总装车间",而它之所以能在"任何 bean 实例化之前"完成这些工作,靠的就是 registry 后处理器这一层 SPI。

3.2 执行入口:AbstractApplicationContext.invokeBeanFactoryPostProcessors

入口在 AbstractApplicationContext.java 第 794-804 行:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (for example, through a @Bean method registered by ConfigurationClassPostProcessor)
	if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
			beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

这个方法本身很薄,真正的逻辑全在 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 里(第 68-209 行,spring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.java)。注意第二个参数 getBeanFactoryPostProcessors()——它返回的是用户通过 AbstractApplicationContext.addBeanFactoryPostProcessor() 手动编程注册的那一批后处理器(存在 context 自己的一个 List<BeanFactoryPostProcessor> 字段里),而不是从 beanFactory 里 getBeanNamesForType 扫出来的那批。这是两条不同的注册路径,下面会看到它们在 delegate 里被区别对待。

3.3 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 完整流程逐段讲

这个方法开头有一段长达 15 行的 WARNING 注释(第 71-82 行),原文摘录关键句:

"the use of multiple lists and multiple passes over the names of processors is intentional. We must ensure that we honor the contracts for PriorityOrdered and Ordered processors. Specifically, we must NOT cause processors to be instantiated (via getBean() invocations) or registered in the ApplicationContext in the wrong order."

这段话是理解整个方法的钥匙:为什么要写这么多段重复的 for 循环?因为每一段循环都对应一次 getBean(),而 getBean() 会真的去实例化后处理器 bean。一旦实例化顺序错了,就违反了 PriorityOrdered/Ordered 契约。 Spring 团队明确说这个方法"看起来可以重构但不能重构",并且在 GitHub 上关闭了一大批想重构它的 PR。

3.3.1 第一阶段:先处理编程注册的那批(context 自己持有的 list)
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();

if (beanFactory instanceof BeanDefinitionRegistry registry) {
	List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
	List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

	for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
		if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
			registryProcessor.postProcessBeanDefinitionRegistry(registry);
			registryProcessors.add(registryProcessor);
		}
		else {
			regularPostProcessors.add(postProcessor);
		}
	}

这段做了三件事:

  1. processedBeans 是一个"已经处理过的后处理器名字集合",后面用来去重。注意它只装 bean name(String),不装实例。
  2. 判断 beanFactory instanceof BeanDefinitionRegistry——7.0.9 里 DefaultListableBeanFactory 同时实现了 ConfigurableListableBeanFactory 和 BeanDefinitionRegistry,所以这个分支几乎总是走 true。else 分支(第 157-160 行)只在极简的、不支持注册表的 beanFactory 里才走。
  3. 遍历 beanFactoryPostProcessors(即 getBeanFactoryPostProcessors() 返回的编程注册列表),按 instanceof 分成两组:
    • 如果是 BeanDefinitionRegistryPostProcessor,立刻调用它的 postProcessBeanDefinitionRegistry(registry)——注意这里没有任何排序,编程注册的后处理器严格按 addBeanFactoryPostProcessor 的添加顺序执行,PriorityOrdered/Ordered 对它们无效(接口 javadoc 明确说过这一点)。
    • 普通 BeanFactoryPostProcessor 先放进 regularPostProcessors,等 registry 组全部跑完再统一调。

为什么编程注册的 registry 后处理器要"立刻"执行?因为用户可能在代码里 ctx.addBeanFactoryPostProcessor(new MyRegistryPostProcessor()) 之后,这个后处理器需要去注册一些额外的 BeanDefinition,而这些额外的 BeanDefinition 里可能又包含新的 registry 后处理器——所以后面才会有"while 循环反复扫描"的设计。

3.3.2 第二阶段:PriorityOrdered 的 registry 后处理器
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		processedBeans.add(ppName);
	}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

逐句拆解:

  • getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false):第二个参数 allowEagerInit=true 表示允许在类型匹配时提前初始化,但第三个参数 includeNonSingletons=false。关键在于——这一步只拿名字,不实例化。
  • 遍历名字,用 isTypeMatch(ppName, PriorityOrdered.class) 判断这个 bean 是否实现了 PriorityOrdered 接口。注意这里用的是 isTypeMatch(基于 BeanDefinition 的元数据类型判断),而不是 getBean(ppName) instanceof PriorityOrdered——因为后者会真的实例化,而此时我们只想挑出"名字"。
  • 对命中的,才真正 beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)——这一步会实例化这个后处理器 bean。实例化后立刻加入 processedBeans 集合,避免后续重复处理。
  • sortPostProcessors:用 OrderComparator(或 beanFactory 里配置的 dependencyComparator)排序。PriorityOrdered 接口本身没有值,排序靠的是 Ordered.getOrder() 返回的 int 值,值小的在前。
  • registryProcessors.addAll(...):把这批已经实例化的 registry 后处理器累计到 registryProcessors 列表里,因为后面要统一调它们的 postProcessBeanFactory。
  • invokeBeanDefinitionRegistryPostProcessors(...):真正循环调用 postProcessor.postProcessBeanDefinitionRegistry(registry),外面包了一层 ApplicationStartup 埋点(第 346-351 行)。
3.3.3 第三阶段:Ordered 的 registry 后处理器
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
	if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		processedBeans.add(ppName);
	}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

与上一段几乎一模一样,唯一区别是:

  1. 重新调了一次 getBeanNamesForType——因为上一段 invokeBeanDefinitionRegistryPostProcessors 可能注册了新的 BeanDefinition(比如 ConfigurationClassPostProcessor 扫描出了新的 @Component),所以要重新拿一遍名字。
  2. 过滤条件变成 !processedBeans.contains(ppName) && isTypeMatch(ppName, Ordered.class)——已经处理过的跳过(去重),且只挑实现了 Ordered 但没有实现 PriorityOrdered 的(因为 PriorityOrdered 已经在上一段被 processedBeans 标记了)。

这里能看出 Spring 的排序三批语义:PriorityOrdered 第一批、Ordered 第二批、无接口第三批,批次之间严格先后,批次内部按 getOrder() 值排序。

3.3.4 第四阶段:while 循环兜底,处理"后处理器注册的后处理器"
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
	reiterate = false;
	postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
	for (String ppName : postProcessorNames) {
		if (!processedBeans.contains(ppName)) {
			currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
			processedBeans.add(ppName);
			reiterate = true;
		}
	}
	sortPostProcessors(currentRegistryProcessors, beanFactory);
	registryProcessors.addAll(currentRegistryProcessors);
	invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
	currentRegistryProcessors.clear();
}

这一段是整个方法最精妙的地方。为什么需要 while(reiterate)?

设想这样一个场景:用户自定义了一个 MyRegistryPostProcessor(无序,没实现 PriorityOrdered/Ordered),它在 postProcessBeanDefinitionRegistry 里又注册了一个 AnotherRegistryPostProcessor 的 BeanDefinition。如果只扫一遍,AnotherRegistryPostProcessor 永远不会被执行。Spring 的做法是:每处理完一批无序的 registry 后处理器,就重新扫一遍 getBeanNamesForType,只要发现还有没处理过的,就 reiterate=true 再来一轮,直到某一轮扫完没有新名字为止。

注意这一批没有排序(虽然代码里仍调了 sortPostProcessors,但无序后处理器彼此间的相对顺序由 beanDefinitionNames 的注册顺序决定),且这一批里 reiterate=true 的设置位置很关键——只有当本轮真的发现了新的未处理名字时才继续循环,否则自然退出,保证终止。

3.3.5 第五阶段:统一调 registry 组与编程组的 postProcessBeanFactory
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

到这里,所有 registry 后处理器的 postProcessBeanDefinitionRegistry 都跑完了,BeanDefinition 的注册阶段结束。现在统一回调它们的 postProcessBeanFactory 方法(注意:这个方法在 6.1 之后对 registry 后处理器来说默认是空实现,但如果用户同时重写了它,就会在这里被调到)。先调 registryProcessors(包括 PriorityOrdered/Ordered/无序三批加编程注册的),再调 regularPostProcessors(编程注册的普通 BFPP)。

3.3.6 第六阶段:处理从 beanFactory 里扫出来的普通 BeanFactoryPostProcessor
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
	if (processedBeans.contains(ppName)) {
		// skip - already processed in first phase above
	}
	else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
	}
	else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
		orderedPostProcessorNames.add(ppName);
	}
	else {
		nonOrderedPostProcessorNames.add(ppName);
	}
}

现在重新扫一遍 BeanFactoryPostProcessor.class 类型的所有 bean 名字。注意:BeanDefinitionRegistryPostProcessor 也是 BeanFactoryPostProcessor,所以它们会出现在这次扫描结果里——但因为它们在前五阶段已经被加入 processedBeans,这里直接 skip。这就是 processedBeans 这个 Set 的核心作用:去重,防止一个 registry 后处理器被当成普通 BFPP 再调一次。

分桶逻辑与 registry 组完全一致:PriorityOrdered 立即 getBean 实例化;Ordered 先记名字;无序先记名字。

// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
	orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
	nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, for example, replacing placeholders in values...
beanFactory.clearMetadataCache();

三批依次执行,最后调 beanFactory.clearMetadataCache() 清掉 merged bean definition 缓存与类型缓存——因为后处理器可能改了 BeanDefinition 的属性值(如 PropertySourcesPlaceholderConfigurer 替换了 ${...} 占位符),之前缓存的合并后元数据已经失效。

3.4 "从 beanFactory 拿" vs "从 registry 注册表拿"——一个关键区分

读者经常困惑:为什么有的后处理器是 beanFactory.getBean(ppName) 拿出来的,有的却是直接从 beanFactoryPostProcessors(context 持有的 list)里拿的?

答案在两条注册路径:

  1. 声明式注册:后处理器本身被声明为一个 bean(XML <bean> 或 @Bean 或 @Component),它的 BeanDefinition 已经躺在 beanFactory 的 beanDefinitionMap 里。容器通过 getBeanNamesForType(BeanFactoryPostProcessor.class) 扫描发现它,再 getBean(ppName) 实例化。这条路径支持 PriorityOrdered/Ordered 排序。
  2. 编程式注册:用户在代码里 ctx.addBeanFactoryPostProcessor(new MyPP()),此时 MyPP 实例已经 new 好了,它根本不在 beanFactory 的 BeanDefinition 里,而是存在 AbstractApplicationContext.beanFactoryPostProcessors 这个独立 list 里。容器直接遍历这个 list,不排序、不 getBean。接口 javadoc 明确说:"any ordering semantics expressed through implementing the PriorityOrdered or Ordered interface will be ignored for programmatically registered post-processors."

理解这一点,就能解释一个常见现象:你写了一个 @Bean 方法返回 BeanFactoryPostProcessor,它会被排序;但如果你在 main 方法里手动 ctx.addBeanFactoryPostProcessor(...),它就按你 add 的顺序先跑,且排在所有声明式注册的之前。

3.5 源码剖析(二):BeanPostProcessor 家族全景

3.5.1 根接口 BeanPostProcessor

BeanPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/config/BeanPostProcessor.java,第 67-111 行)是整个 Bean 级扩展点的根。它只声明两个 default 方法:

public interface BeanPostProcessor {

	default @Nullable Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	default @Nullable Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

两个方法都在 initializeBean 阶段被调用:postProcessBeforeInitialization 在 invokeInitMethods(即 afterPropertiesSet/init-method)之前,postProcessAfterInitialization 在之后。注意 javadoc 第 91-97 行那个关键说明:"In case of a FactoryBean, this callback will be invoked for both the FactoryBean instance and the objects created by the FactoryBean."——FactoryBean 本身和它 getObject() 出来的对象,都会走过 postProcessAfterInitialization。这正是 AOP 自动代理能作用于 FactoryBean 产物的原因。

另一个关键约定在第 95-97 行:"This callback will also be invoked after a short-circuiting triggered by a InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation method, in contrast to all other BeanPostProcessor callbacks."——也就是说,如果 postProcessBeforeInstantiation 短路返回了非 null 对象,那么后续的 populateBean、initializeBean 全被跳过,但唯独 postProcessAfterInitialization 还会被补调一次(见 AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation 第 1132-1134 行)。这个"例外"是 AOP 代理能在短路路径上仍然生效的关键。

3.5.2 调用位置:AbstractAutowireCapableBeanFactory.initializeBean

两个方法的调用点在 AbstractAutowireCapableBeanFactory.initializeBean(spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java,第 1797-1822 行):

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	// Skip initialization of a NullBean
	if (bean.getClass() == NullBean.class) {
		return bean;
	}

	invokeAwareMethods(beanName, bean);

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
	}
	if (mbd == null || !mbd.isSynthetic()) {
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

这段代码把 Bean 级扩展点的调用顺序写得清清楚楚:

  1. invokeAwareMethods(第 1803 行):inline 回调 BeanNameAware/BeanClassLoaderAware/BeanFactoryAware;
  2. applyBeanPostProcessorsBeforeInitialization(第 1807 行):遍历所有已注册的 BeanPostProcessor,调 postProcessBeforeInitialization;
  3. invokeInitMethods(第 1811 行):先 InitializingBean.afterPropertiesSet(),再自定义 init-method;
  4. applyBeanPostProcessorsAfterInitialization(第 1818 行):遍历所有 BeanPostProcessor,调 postProcessAfterInitialization。

注意第 1806、1817 行的 !mbd.isSynthetic() 判断——合成的 BeanDefinition(如 AOP 内部为 advisor 注册的合成 bean)不回调普通 BeanPostProcessor,避免对内部基础设施 bean 做无谓的代理。

两个 apply 方法的实现很简单(第 421-447 行):

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

这里有一个容易被忽略的细节:如果某个后处理器返回 null,整个链路立刻终止并返回上一个非 null 的结果。这不是"跳过这一个",而是"短路整个后续链"。BeanPostProcessor 接口 javadoc 第 78 行明确写了:"if null, no subsequent BeanPostProcessors will be invoked"。绝大多数实现都原样返回 bean,但如果你写的自定义后处理器在异常分支里不小心返回了 null,就会把后面的 AOP 代理、@PostConstruct 处理等全部"截断",这是一个隐蔽的坑。

3.5.3 InstantiationAwareBeanPostProcessor:三个时机

InstantiationAwareBeanPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java)继承自 BeanPostProcessor,新增三个方法:

default @Nullable Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	return null;
}

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
	return true;
}

default @Nullable PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
		throws BeansException {
	return pvs;
}
postProcessBeforeInstantiation:实例化前的"短路"

这个方法在 AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(第 1123-1140 行)里被调用:

@SuppressWarnings("deprecation")
protected @Nullable Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

调用链是:createBean(第 530 行附近)先调 resolveBeforeInstantiation,如果返回非 null,就直接 return bean,根本不进入 doCreateBean。这意味着:

  • 不会执行 createBeanInstance(没有 new 对象);
  • 不会执行 applyMergedBeanDefinitionPostProcessors;
  • 不会执行 populateBean(没有属性填充);
  • 不会执行 initializeBean 的 invokeAwareMethods、postProcessBeforeInitialization、invokeInitMethods;
  • 唯独会补调一次 applyBeanPostProcessorsAfterInitialization(第 1133 行),让 AOP 等后处理器有机会包装短路产物。

applyBeanPostProcessorsBeforeInstantiation 的实现(第 1153-1161 行)同样是"第一个返回非 null 的就立刻返回":

protected @Nullable Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
		if (result != null) {
			return result;
		}
	}
	return null;
}

这意味着多个 InstantiationAwareBeanPostProcessor 同时存在时,只有第一个返回非 null 的会生效,后面的根本不会被调到。AbstractAutoProxyCreator(AOP 自动代理的基类,spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java)正是利用这个钩子:它在 postProcessBeforeInstantiation 里检查这个 bean 是否需要 TargetSource(如 LazyInitTargetSourceCreator),如果需要就直接返回一个代理对象,短路掉正常实例化。

postProcessAfterInstantiation:实例化后、属性填充前

这个方法在 populateBean 开头被调(第 1416-1422 行):

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
	for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
			return;
		}
	}
}

注意返回 false 会直接 return,整个 populateBean 终止——后续的 autowireByName/autowireByType/postProcessProperties/applyPropertyValues 全不执行。接口 javadoc 第 84-85 行明确说:"Returning false will also prevent any subsequent InstantiationAwareBeanPostProcessor instances being invoked on this bean instance."

postProcessProperties:属性值的最后一次加工

这个方法在 populateBean 的属性应用前被调(第 1439-1450 行):

if (hasInstantiationAwareBeanPostProcessors()) {
	if (pvs == null) {
		pvs = mbd.getPropertyValues();
	}
	for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
		if (pvsToUse == null) {
			return;
		}
		pvs = pvsToUse;
	}
}

AutowiredAnnotationBeanPostProcessor.postProcessProperties 在这里完成 @Autowired/@Value 的字段与方法注入(它在内部反射注入后,把 pvs 原样返回)。返回 null 同样会终止属性填充。

关于 postProcessPropertyValues 的废弃:7.0.9 的 InstantiationAwareBeanPostProcessor 接口里已经没有 postProcessPropertyValues 方法了。这个方法在 Spring 5.1 被 postProcessProperties 取代并标记 @Deprecated,在 Spring 6.x 被彻底移除。本章任务书里提到的"postProcessPropertyValues 的废弃",在 7.0.9 源码里就是"已不存在"——读者若看到旧教程里同时讲这两个方法,要以 7.0.9 为准。

3.5.4 SmartInstantiationAwareBeanPostProcessor:四个预测/早期引用方法

SmartInstantiationAwareBeanPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java)继承自 InstantiationAwareBeanPostProcessor,新增四个方法:

default @Nullable Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
	return null;
}

default Class<?> determineBeanType(Class<?> beanClass, String beanName) throws BeansException {
	return beanClass;
}

default Constructor<?> @Nullable [] determineCandidateConstructors(Class<?> beanClass, String beanName)
		throws BeansException {
	return null;
}

default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
	return bean;
}

各自的调用位置:

  • predictBeanType:在 AbstractAutowireCapableBeanFactory.predictBeanType(第 652-660 行)里被调,用于在不实例化 bean 的情况下预测它的最终类型。这在 getBeanNamesForType 类型匹配时至关重要——比如 AOP 代理后类型会变,容器需要提前知道"这个 bean 最终会是 X 类型的代理"。
  • determineBeanType:6.0 新增,比 predictBeanType 更"重"——允许实现类真正去创建/初始化一个代理类来确定类型。默认实现原样返回 beanClass。
  • determineCandidateConstructors:在 AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(第 1319 行)里被调。AutowiredAnnotationBeanPostProcessor 重写了它,用来找 @Autowired 标注的构造器——这就是为什么多构造器场景下 Spring 能选出"带 @Autowired 的那个"。
  • getEarlyBeanReference:在 AbstractAutowireCapableBeanFactory.getEarlyBeanReference(第 966-974 行)里被调,而这个方法被包在 doCreateBean 的三级缓存 addSingletonFactory 里(第 596 行):
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

AbstractAutoProxyCreator 重写了 getEarlyBeanReference,在循环依赖场景下提前为 bean 生成 AOP 代理——这就是三级缓存能解决"循环依赖 + AOP"共存问题的核心回调。如果没有这个钩子,循环依赖时另一方拿到的会是原始对象而不是代理,导致代理被绕过。

3.5.5 MergedBeanDefinitionPostProcessor:注解元数据收集的挂载点

MergedBeanDefinitionPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java)继承自 BeanPostProcessor,只有一个抽象方法:

void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

default void resetBeanDefinition(String beanName) {
}

它的调用点在 AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(第 1110-1114 行):

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
		processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
	}
}

而这个方法在 doCreateBean 里的位置非常关键(第 573-585 行):

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
	if (!mbd.postProcessed) {
		try {
			applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Post-processing of merged bean definition failed", ex);
		}
		mbd.markAsPostProcessed();
	}
}

它发生在 createBeanInstance 之后、populateBean 之前。为什么必须卡在这个位置?因为:

  1. 此时 bean 已经 new 出来了,beanType 已经确定(instanceWrapper.getWrappedClass()),后处理器可以拿到真实的 Class 去反射扫描注解;
  2. 但属性还没填充,后处理器有机会提前缓存注解元数据(如 AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition 会扫描所有 @Autowired 字段/方法,构造一个 InjectionMetadata 缓存起来),等后面 populateBean → postProcessProperties 时直接用缓存,避免每个 bean 都重复反射扫描。

AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(第 279 行)正是做这件事:它扫描 beanClass 上的 @Autowired/@Value/@Inject,把结果存入 this.injectionMetadataCache(一个 ConcurrentHashMap)。后续 postProcessProperties 直接从缓存取,O(1)。

注意 synchronized (mbd.postProcessingLock) 和 !mbd.postProcessed 双重检查——同一个 merged BeanDefinition 只会被处理一次,多线程并发创建同一个 bean 时靠这个锁保护(7.0 支持并行实例化单例)。

3.5.6 DestructionAwareBeanPostProcessor:销毁前的回调

DestructionAwareBeanPostProcessor(spring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java)新增两个方法:

void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

default boolean requiresDestruction(Object bean) {
	return true;
}

它的调用点不在 AbstractAutowireCapableBeanFactory,而在 DisposableBeanAdapter.destroy(spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java,第 199-200 行):

for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
	processor.postProcessBeforeDestruction(this.bean, this.beanName);
}

而 requiresDestruction 在 DisposableBeanAdapter.hasApplicableProcessors(第 466-470 行)里被用来判断:这个 bean 是否真的需要被注册为 disposable。如果所有 DestructionAwareBeanPostProcessor.requiresDestruction(bean) 都返回 false,且 bean 本身没实现 DisposableBean、没配 destroy-method,那么容器不会把它加入 disposableBeans map——这是一个优化,避免无意义的销毁登记。InitDestroyAnnotationBeanPostProcessor(处理 @PreDestroy/@PostConstruct)就重写了 requiresDestruction:只有 bean 类里真的有 @PreDestroy 注解方法时才返回 true。

DisposableBeanAdapter 本身是在 AbstractAutowireCapableBeanFactory.registerDisposableBeanIfNecessary(doCreateBean 末尾第 641 行调用)里被创建并注册到 DefaultSingletonBeanRegistry.disposableBeans(一个 LinkedHashMap,按注册顺序保留)的。销毁时 destroySingletons(第 693-718 行)逆序遍历这个 map:

String[] disposableBeanNames;
synchronized (this.disposableBeans) {
	disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
	destroySingleton(disposableBeanNames[i]);
}

逆序销毁的语义是:后创建的 bean 先销毁,这符合"被依赖者最后销毁"的直觉(因为先创建的通常是基础组件)。

3.6 registerBeanPostProcessors:三批注册与内部后处理器的"再注册"

BeanPostProcessor 的注册入口在 AbstractApplicationContext.registerBeanPostProcessors(第 811-813 行),直接委托给 PostProcessorRegistrationDelegate.registerBeanPostProcessors(第 211-292 行)。这个方法与 invokeBeanFactoryPostProcessors 一样,开头有同样的 WARNING 注释,强调"多次遍历是刻意的,不能重构"。

3.6.1 先注册一个"监听器" BeanPostProcessorChecker
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs a warn message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(
		new BeanPostProcessorChecker(beanFactory, postProcessorNames, beanProcessorTargetCount));

这里先加了一个框架内置的 BeanPostProcessorChecker(第 391-455 行)。它的作用是告警:如果在"实例化 BeanPostProcessor bean"的过程中,某个普通 bean 被提前创建了(因为后处理器的构造器/@Autowired 依赖了它),那么这个普通 bean 就不可能被所有 BeanPostProcessor 处理到——因为它创建时,后处理器链还没注册完。BeanPostProcessorChecker.postProcessAfterInitialization 会检测这种情况并打 warn 日志(第 437-442 行):"is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)"。

这正是接口 javadoc 反复强调"用 static @Bean 方法声明后处理器"的原因——static 方法不依赖配置类实例,不会触发配置类里其他 bean 的提前初始化。

3.6.2 三批分桶
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		priorityOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
		orderedPostProcessorNames.add(ppName);
	}
	else {
		nonOrderedPostProcessorNames.add(ppName);
	}
}

注意这里比 BFPP 多了一个 internalPostProcessors 桶。它专门收集那些同时实现了 MergedBeanDefinitionPostProcessor 的后处理器——不管它们属于 PriorityOrdered、Ordered 还是无序批,都会被额外塞进 internalPostProcessors。这是因为 MergedBeanDefinitionPostProcessor 需要在所有普通后处理器注册完之后再注册一次,确保它们的 postProcessMergedBeanDefinition 能在所有 bean 创建前生效(见第 3.6.4 节)。

3.6.3 三批依次注册
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
	orderedPostProcessors.add(pp);
	if (pp instanceof MergedBeanDefinitionPostProcessor) {
		internalPostProcessors.add(pp);
	}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessNames) {
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
	nonOrderedPostProcessors.add(pp);
	if (pp instanceof MergedBeanDefinitionPostProcessor) {
		internalPostProcessors.add(pp);
	}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

注册顺序是:PriorityOrdered(先排序后批量加)→ Ordered(先 getBean 再排序再批量加)→ 无序(直接批量加,不排序)。registerBeanPostProcessors 私有方法(第 371-383 行)对 AbstractBeanFactory 走批量 addBeanPostProcessors(List),因为底层是 CopyOnWriteArrayList,批量加比逐个加高效。

3.6.4 内部后处理器"再注册"与 ApplicationListenerDetector
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

最后两步是 7.0.9 的细节:

  1. internalPostProcessors(即所有 MergedBeanDefinitionPostProcessor 实现)被再注册一次。因为 CopyOnWriteArrayList 的 add 是追加到末尾,再注册一次意味着把它们从原位置"挪到链尾"。为什么?因为 MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition 必须在所有 bean 创建前完成元数据收集,而把它们放在链尾,可以保证它们的 postProcessBeforeInitialization/postProcessAfterInitialization 在 AOP 代理等之后执行——AutowiredAnnotationBeanPostProcessor 就是一个典型例子。
  2. ApplicationListenerDetector 被 new 出来直接 add(不经过 getBean),放在链的最末尾。它的作用是:如果某个 bean 实现了 ApplicationListener,就把它注册到 context 的监听器列表里。注释说"moving it to the end of the processor chain (for picking up proxies etc)"——因为代理对象也可能是 ApplicationListener,放在最后能拿到最终的代理对象而不是原始对象。

3.7 Aware 接口族:两路注入的秘密

3.7.1 哪些 Aware 由容器 inline 回调

AbstractAutowireCapableBeanFactory.invokeAwareMethods(第 1824-1839 行)只处理三个 Aware:

private void invokeAwareMethods(String beanName, Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware beanNameAware) {
			beanNameAware.setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				beanClassLoaderAware.setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware beanFactoryAware) {
			beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

这三个接口都在 spring-beans 模块:

  • BeanNameAware(spring-beans/src/main/java/org/springframework/beans/factory/BeanNameAware.java):回调 setBeanName(String),让 bean 知道自己在容器里的名字;
  • BeanClassLoaderAware(spring-beans/src/main/java/org/springframework/beans/factory/BeanClassLoaderAware.java):回调 setBeanClassLoader(ClassLoader);
  • BeanFactoryAware(spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryAware.java):回调 setBeanFactory(BeanFactory),把 beanFactory 本身注入。

为什么这三个要"inline"?因为它们在 initializeBean 的最开头(第 1803 行)就被调用,早于任何 BeanPostProcessor。这保证了:即使一个 bean 是 BeanFactoryAware,它在后续 postProcessBeforeInitialization 阶段也能拿到 beanFactory 去做 lookup。

3.7.2 其余 Aware 由 ApplicationContextAwareProcessor 回调

其余 Aware 接口在 spring-context 模块,因为它们依赖 application context 层的概念。这些 Aware 由 ApplicationContextAwareProcessor(spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java)这个 BeanPostProcessor 来回调。它的 postProcessBeforeInitialization(第 82-88 行):

@Override
public @Nullable Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	if (bean instanceof Aware) {
		invokeAwareInterfaces(bean);
	}
	return bean;
}

private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof EnvironmentAware environmentAware) {
		environmentAware.setEnvironment(this.applicationContext.getEnvironment());
	}
	if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {
		embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);
	}
	if (bean instanceof ResourceLoaderAware resourceLoaderAware) {
		resourceLoaderAware.setResourceLoader(this.applicationContext);
	}
	if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {
		applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);
	}
	if (bean instanceof MessageSourceAware messageSourceAware) {
		messageSourceAware.setMessageSource(this.applicationContext);
	}
	if (bean instanceof ApplicationStartupAware applicationStartupAware) {
		applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());
	}
	if (bean instanceof ApplicationContextAware applicationContextAware) {
		applicationContextAware.setApplicationContext(this.applicationContext);
	}
}

回调顺序严格按 javadoc 声明:EnvironmentAware → EmbeddedValueResolverAware → ResourceLoaderAware → ApplicationEventPublisherAware → MessageSourceAware → ApplicationStartupAware → ApplicationContextAware。这个顺序是刻意的:ApplicationContextAware 放最后,因为前面几个 Aware 提供的对象(Environment、ResourceLoader 等)都是 ApplicationContext 的一部分,先设置"小"的,再设置"大"的。

3.7.3 为什么要分两路

读者会问:为什么不把所有 Aware 都塞进 invokeAwareMethods?答案是模块依赖:

  • spring-beans 模块不能依赖 spring-context。BeanFactory、BeanName、ClassLoader 都是 spring-beans 层的概念,所以对应的 Aware 可以在 AbstractAutowireCapableBeanFactory 里 inline 调;
  • ApplicationContext、Environment、MessageSource、ApplicationEventPublisher 是 spring-context 层的概念,spring-beans 根本不知道它们存在。所以容器设计了一个"反向钩子":AbstractApplicationContext.prepareBeanFactory(第 736 行)把 ApplicationContextAwareProcessor 这个 BeanPostProcessor 注册进 beanFactory,由它在 postProcessBeforeInitialization 阶段回调那些 context 层的 Aware。

prepareBeanFactory 里还有一段配套的 ignoreDependencyInterface(第 737-743 行):

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

ignoreDependencyInterface 的作用是:告诉容器"当你做 autowiring 时,不要把这些 Aware 接口当成需要自动注入的依赖"。因为这些 Aware 由 ApplicationContextAwareProcessor 专门回调,而不是靠 @Autowired 自动装配。如果不 ignore,容器可能会试图找一个 Environment 类型的 bean 去注入 setEnvironment 方法,造成冲突。

3.7.4 Aware 回调 vs BeanPostProcessor 的先后

把两路拼起来,一个普通 bean 在 initializeBean 里的完整顺序是:

initializeBean(beanName, bean, mbd)
 ├─ invokeAwareMethods()                    ← BeanName/BeanClassLoader/BeanFactory (inline, spring-beans)
 ├─ applyBeanPostProcessorsBeforeInitialization()
 │    └─ ApplicationContextAwareProcessor.postProcessBeforeInitialization()
 │         └─ invokeAwareInterfaces()       ← Environment/EmbeddedValueResolver/ResourceLoader/
 │                                            ApplicationEventPublisher/MessageSource/
 │                                            ApplicationStartup/ApplicationContext
 │    └─ 其他 BeanPostProcessor.postProcessBeforeInitialization()
 │         (如 InitDestroyAnnotationBeanPostProcessor 调 @PostConstruct)
 ├─ invokeInitMethods()                      ← InitializingBean.afterPropertiesSet() + init-method
 └─ applyBeanPostProcessorsAfterInitialization()
      └─ 其他 BeanPostProcessor.postProcessAfterInitialization()
           (如 AbstractAutoProxyCreator 生成 AOP 代理)

关键结论:BeanNameAware 等三个 inline Aware 一定先于 ApplicationContextAware 等 context Aware;所有 Aware 回调都先于 @PostConstruct(由 InitDestroyAnnotationBeanPostProcessor 在 postProcessBeforeInitialization 里处理);所有 Aware 回调都先于 InitializingBean.afterPropertiesSet。这就是为什么你在 setApplicationContext 里能拿到 beanFactory(因为 BeanFactoryAware 已经先调过了),但在 afterPropertiesSet 里才能安全地使用那些需要完整容器状态的 bean。

3.8 源码剖析(三):注册机制三件套——ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar

这三个扩展点都在 spring-context/src/main/java/org/springframework/context/annotation/ 包下,它们不是由 PostProcessorRegistrationDelegate 直接驱动的,而是由 ConfigurationClassPostProcessor(一个 BeanDefinitionRegistryPostProcessor)在解析 @Configuration 类时回调。换句话说,它们是"后处理器的后处理器"——运行在 registry 后处理器的内部。

3.8.1 ImportSelector:根据注解元数据返回要导入的类名

ImportSelector(spring-context/src/main/java/org/springframework/context/annotation/ImportSelector.java)只有一个核心方法:

String[] selectImports(AnnotationMetadata importingClassMetadata);

default @Nullable Predicate<String> getExclusionFilter() {
	return null;
}

selectImports 接收"导入它的那个 @Configuration 类"的注解元数据(AnnotationMetadata),返回一组要导入的类全限定名。框架拿到这些名字后,会把它们当成新的 @Configuration 类递归解析。javadoc 第 30-47 行还说明:ImportSelector 实现类本身可以实现 EnvironmentAware/BeanFactoryAware/BeanClassLoaderAware/ResourceLoaderAware,这些 Aware 回调会在 selectImports 之前发生——或者更简单地,直接在构造器里接收 Environment/BeanFactory/ClassLoader/ResourceLoader 作为参数。

getExclusionFilter 是 5.2.4 新增的:返回一个 Predicate<String>,对递归导入的类名做二次过滤,返回 true 的类会被跳过,连类文件都不加载。这在做条件化装配时很有用。

典型例子:@EnableAsync 通过 @Import(AsyncConfigurationSelector.class) 导入一个 AdviceModeImportSelector,后者根据 @EnableAsync 的 mode 属性决定导入 ProxyAsyncConfiguration 还是 AspectJAsyncConfiguration。

3.8.2 DeferredImportSelector:延迟到最后,并支持跨选择器分组

DeferredImportSelector(spring-context/src/main/java/org/springframework/context/annotation/DeferredImportSelector.java)继承自 ImportSelector,新增一个方法:

default @Nullable Class<? extends Group> getImportGroup() {
	return null;
}

以及一个嵌套接口 Group(第 56-123 行):

interface Group {
	void process(AnnotationMetadata metadata, DeferredImportSelector selector);
	Iterable<Entry> selectImports();

	class Entry {
		private final AnnotationMetadata metadata;
		private final String importClassName;
		// ...
	}
}

Deferred 的语义在 javadoc 第 24-26 行:"A variation of ImportSelector that runs after all @Configuration beans have been processed." 普通 ImportSelector 在遇到 @Import 时立刻处理,而 DeferredImportSelector 会被框架收集起来,等所有普通 @Configuration 类解析完之后再统一处理。这在做条件化装配时很关键:比如 @EnableAutoConfiguration(Spring Boot)是一个 DeferredImportSelector,它必须等用户自己写的所有 @Configuration 都注册完,才能决定"自动配置哪些 bean"——这样用户的显式配置才能覆盖自动配置。

Group 的作用是跨选择器排序。多个 DeferredImportSelector 如果返回同一个 Group 类,框架会把它们的 process 调用聚合到一个 Group 实例里,最后统一调 selectImports() 返回最终的导入列表。这允许一个 Group 跨多个 selector 做全局排序、去重、合并。@EnableAutoConfiguration 用的 AutoConfigurationImportSelector 就返回了 AutoConfigurationGroup,它会把所有 @Configuration 类的元数据收集起来,按 @Order/@AutoConfigureBefore/@AutoConfigureAfter 排序后再输出。

javadoc 第 28-30 行还说明:DeferredImportSelector 实现类可以实现 Ordered 或加 @Order 来指示跨选择器的优先级。

3.8.3 ImportBeanDefinitionRegistrar:直接拿 registry 注册 bean

ImportBeanDefinitionRegistrar(spring-context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java)与前两者不同:它不返回类名,而是直接拿到 BeanDefinitionRegistry,自己调 registerBeanDefinition 注册 BeanDefinition。典型签名:

public interface ImportBeanDefinitionRegistrar {
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator);
	// ...
}

与 ImportSelector 的区别:

  • ImportSelector 返回类名,框架把这些类当成 @Configuration 处理——适合导入"已经写好的配置类";
  • ImportBeanDefinitionRegistrar 直接操作 registry——适合"动态生成" BeanDefinition,比如根据注解属性批量注册 MapperProxy、FeignClient、RibbonClient 等。

典型例子:@EnableFeignClients 通过 @Import(FeignClientsRegistrar.class) 导入一个 ImportBeanDefinitionRegistrar,后者扫描所有 @FeignClient 注解的接口,为每个接口注册一个 FeignClientFactoryBean 的 BeanDefinition。Spring 官方的 @EnableConfigurationProperties、@MapperScan 也都是这个模式。

3.8.4 三种 @Import 路径的扩展点视角

@Import 注解本身有三种用法:

  1. @Import(SomeConfiguration.class):直接导入一个普通 @Configuration 类;
  2. @Import(SomeImportSelector.class):导入一个 ImportSelector/DeferredImportSelector;
  3. @Import(SomeRegistrar.class):导入一个 ImportBeanDefinitionRegistrar。

这三种路径的解析都由 ConfigurationClassParser(spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java)在 ConfigurationClassPostProcessor 的驱动下完成。从扩展点视角看,它们的区别是:

路径回调接口何时执行能做什么
导入普通类无立即把该类当 @Configuration 解析
导入 ImportSelectorselectImports立即(Deferred 则延迟)返回类名数组,由框架递归解析
导入 ImportBeanDefinitionRegistrarregisterBeanDefinitions立即拿 registry 直接注册任意 BeanDefinition

注意 ImportSelector 和 ImportBeanDefinitionRegistrar 都可以实现 EnvironmentAware/BeanFactoryAware 等 Aware 接口,ConfigurationClassParser 在实例化它们后会回调这些 Aware——这是它们能拿到环境信息、beanFactory 的方式。

3.9 源码剖析(四):FactoryBean 与 SmartFactoryBean

3.9.1 FactoryBean 接口语义

FactoryBean(spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java)是一个特殊的 bean:它本身是一个工厂,getObject() 返回的才是真正暴露给容器的 bean。核心方法:

public interface FactoryBean<T> {
	T getObject() throws Exception;
	Class<?> getObjectType();
	default boolean isSingleton() { return true; }
}
  • getObject():工厂方法,返回实际对象;
  • getObjectType():返回对象类型(不实例化),用于类型匹配;
  • isSingleton():是否单例。如果返回 true,容器会缓存 getObject() 的结果;如果 false,每次 getBean 都调一次 getObject()。

getBean("&name") 的语义:beanFactory 里 beanName 对应的是 FactoryBean 实例本身,beanName 前面加 & 前缀(FactoryBean.FACTORY_BEAN_PREFIX,即 "&")才是拿 FactoryBean 自己。这个逻辑在 AbstractBeanFactory.doGetBean 里处理。

3.9.2 getObjectFromFactoryBean:单例缓存与后处理

FactoryBeanRegistrySupport.getObjectFromFactoryBean(spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java,第 119-187 行)是 FactoryBean 产物的获取入口。关键逻辑:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, @Nullable Class<?> requiredType,
		String beanName, boolean shouldPostProcess) {

	if (factory.isSingleton() && containsSingleton(beanName)) {
		Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
		boolean locked;
		if (lockFlag == null) {
			this.singletonLock.lock();
			locked = true;
		}
		else {
			locked = (lockFlag && this.singletonLock.tryLock());
		}
		try {
			if (factory instanceof SmartFactoryBean<?>) {
				// A SmartFactoryBean may return multiple object types -> do not cache.
				Object object = doGetObjectFromFactoryBean(factory, requiredType, beanName);
				if (shouldPostProcess) {
					object = postProcessObjectFromSingletonFactoryBean(object, beanName, locked);
				}
				return object;
			}
			else {
				synchronized (factory) {
					Object object = this.factoryBeanObjectCache.get(beanName);
					if (object == null) {
						object = doGetObjectFromFactoryBean(factory, requiredType, beanName);
						Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
						if (alreadyThere != null) {
							object = alreadyThere;
						}
						else {
							if (shouldPostProcess) {
								object = postProcessObjectFromSingletonFactoryBean(object, beanName, locked);
							}
							if (containsSingleton(beanName)) {
								this.factoryBeanObjectCache.put(beanName, object);
							}
						}
					}
					return object;
				}
			}
		}
		finally {
			if (locked) {
				this.singletonLock.unlock();
			}
		}
	}
	else {
		Object object = doGetObjectFromFactoryBean(factory, requiredType, beanName);
		if (shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

几个 7.0.9 的关键点:

  1. factoryBeanObjectCache(第 46 行)是 ConcurrentHashMap,缓存单例 FactoryBean 的 getObject() 结果。注意它与 DefaultSingletonBeanRegistry.singletonObjects 是两个独立的缓存:singletonObjects 存 FactoryBean 实例本身,factoryBeanObjectCache 存 FactoryBean 产出的对象。
  2. SmartFactoryBean 不缓存:第 133-141 行,如果 factory instanceof SmartFactoryBean,直接调 doGetObjectFromFactoryBean 并后处理,不查 factoryBeanObjectCache。注释说"A SmartFactoryBean may return multiple object types -> do not cache"——因为 SmartFactoryBean 可能按 requiredType 返回不同对象,缓存会错乱。
  3. 普通单例 FactoryBean 双重检查:在 synchronized(factory) 块里先查 factoryBeanObjectCache,没有再 doGetObjectFromFactoryBean,然后再查一次 alreadyThere——防止在 getObject() 调用期间,循环依赖触发的其他线程已经把对象放进去了。
  4. shouldPostProcess 与 AOP 的关系:postProcessObjectFromSingletonFactoryBean(第 227-247 行)最终调 postProcessObjectFromFactoryBean,而这个方法在 AbstractBeanFactory 的子类里被重写——AbstractAutowireCapableBeanFactory 重写它为:
// AbstractAutowireCapableBeanFactory 中(约第 1936 行)
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
	return applyBeanPostProcessorsAfterInitialization(object, beanName);
}

也就是说,FactoryBean 产出的单例对象,会再走一遍 postProcessAfterInitialization——这正是 AOP 自动代理能作用于 FactoryBean 产物的原因。AbstractAutoProxyCreator.postProcessAfterInitialization 会检查 FactoryBean 产出的对象是否需要代理,需要就包一层代理。

  1. 锁策略:7.0.9 用 singletonLock(ReentrantLock)+ isCurrentThreadAllowedToHoldSingletonLock() 判断当前线程是否允许拿锁。并行实例化场景下,后台线程用 tryLock 快速失败,避免与主线程死锁。

3.9.3 SmartFactoryBean 扩展

SmartFactoryBean(spring-beans/src/main/java/org/springframework/beans/factory/SmartFactoryBean.java)继承自 FactoryBean,新增:

boolean isEagerInit();

isEagerInit() 返回 true 表示这个 FactoryBean 应该在容器启动时就初始化(即使它的类型没人依赖)。普通 FactoryBean 是懒初始化的——只有 getBean("name") 被调时才 getObject()。SmartFactoryBean 通过 isEagerInit=true 告诉容器:启动时就准备好我。doGetObjectFromFactoryBean(第 197-222 行)还支持 SmartFactoryBean.getObject(requiredType) 按类型取对象。

3.10 源码剖析(五):SmartInitializingSingleton

SmartInitializingSingleton(spring-beans/src/main/java/org/springframework/beans/factory/SmartInitializingSingleton.java)只有一个方法:

public interface SmartInitializingSingleton {
	void afterSingletonsInstantiated();
}

调用点在 DefaultListableBeanFactory.preInstantiateSingletons(spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java,第 1141-1150 行):

// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
	Object singletonInstance = getSingleton(beanName, false);
	if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
		StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
				.tag("beanName", beanName);
		smartSingleton.afterSingletonsInstantiated();
		smartInitialize.end();
	}
}

这个循环发生在所有非懒加载单例都创建完毕之后(前面第 1118-1134 行已经遍历 beanNames 完成了 preInstantiateSingleton)。此时容器状态是:所有普通单例都已就绪,但 finishRefresh 还没跑,ContextRefreshedEvent 还没发,SmartLifecycle.start() 还没调。

它与 ContextRefreshedEvent 的区别:

  • afterSingletonsInstantiated:在 preInstantiateSingletons 末尾同步调用,此时 LifecycleProcessor 还没初始化,publishEvent 可能还没准备好;适合做"依赖所有单例就绪、但不依赖 lifecycle/事件机制"的初始化(如 EventListenerMethodProcessor 在这里注册 @EventListener 方法)。
  • ContextRefreshedEvent:在 finishRefresh 最后发布,此时 lifecycle 已启动、事件多播器已就绪;适合做"容器完全就绪后"的钩子。

7.0.9 的并行实例化场景下(bootstrapExecutor 配置后,部分 bean 在后台线程创建),preInstantiateSingletons 会先 CompletableFuture.allOf(...).join() 等所有后台 future 完成(第 1129 行),再进入这个 afterSingletonsInstantiated 循环——保证所有单例(无论主线程还是后台线程创建)都就绪后才回调。

3.11 源码剖析(六):Lifecycle、Phased、SmartLifecycle 与 LifecycleProcessor

3.11.1 三个接口的层次

Lifecycle(spring-context/src/main/java/org/springframework/context/Lifecycle.java)是最基础的生命周期接口:

public interface Lifecycle {
	void start();
	void stop();
	boolean isRunning();
}

Phased(spring-context/src/main/java/org/springframework/context/Phased.java)只提供 int getPhase(),用于排序。

SmartLifecycle(spring-context/src/main/java/org/springframework/context/SmartLifecycle.java)继承自 Lifecycle,新增:

boolean isAutoStartup();
default void stop(Runnable callback) {}
int getPhase();
  • isAutoStartup():是否在容器 refresh 完成时自动 start。返回 false 的 bean 只在显式调 lifecycleProcessor.start() 时才启动;
  • stop(Runnable):异步停止回调,容器在 stop 完成后调 callback.run(),用于实现优雅停机(带超时等待);
  • getPhase():启停顺序值。

3.11.2 LifecycleProcessor 的初始化与调用位置

AbstractApplicationContext.finishRefresh(第 1002-1017 行):

protected void finishRefresh() {
	// Reset common introspection caches in Spring's core infrastructure.
	resetCommonCaches();

	// Clear context-level resource caches (such as ASM metadata from scanning).
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));
}

initLifecycleProcessor 会创建一个 DefaultLifecycleProcessor 实例并注册为 bean(如果用户没自定义的话)。onRefresh() 触发所有 SmartLifecycle 的自动启动。

关闭路径在 doClose(第 1197-1204 行):

// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
	try {
		this.lifecycleProcessor.onClose();
	}
	catch (Throwable ex) {
		logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
	}
}

先 onClose() 停所有 lifecycle bean,再 destroyBeans()。顺序很重要:先停业务逻辑(lifecycle),再销毁 bean 实例(disposable)。

3.11.3 DefaultLifecycleProcessor:按 phase 分组的启停

DefaultLifecycleProcessor.startBeans(第 365-381 行):

private void startBeans(boolean autoStartupOnly) {
	Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
	Map<Integer, LifecycleGroup> phases = new TreeMap<>();

	lifecycleBeans.forEach((beanName, bean) -> {
		if (!autoStartupOnly || isAutoStartupCandidate(beanName, bean)) {
			int startupPhase = getPhase(bean);
			phases.computeIfAbsent(
					startupPhase, phase -> new LifecycleGroup(phase, lifecycleBeans, autoStartupOnly, false))
						.add(beanName, bean);
		}
	});

	if (!phases.isEmpty()) {
		phases.values().forEach(LifecycleGroup::start);
	}
}

关键设计:

  1. TreeMap<Integer, LifecycleGroup>:key 是 phase 值,TreeMap 自然按 key 升序。启动时 phases.values().forEach(LifecycleGroup::start) 按 phase 从小到大——phase 小的先启动;
  2. autoStartupOnly:onRefresh() 调 startBeans(true),只启动 isAutoStartup()=true 的;显式调 start() 时 startBeans(false),启动所有;
  3. getPhase(bean)(第 562-564 行):bean instanceof Phased phased ? phased.getPhase() : 0——没实现 Phased 的 Lifecycle bean 默认 phase=0。

关闭时 stopBeans(第 436-450 行)用 TreeMap<>(Comparator.reverseOrder()),phase 从大到小停——后启动的先停,这是依赖倒置的标准做法(数据库连接池 phase 通常很低,最后停;web 服务器 phase 高,最先停)。

LifecycleGroup.start(第 603-631 行)还支持 6.2.6 新增的并发启动:如果某个 phase 配置了 setConcurrentStartupForPhase(phase, timeout),该 phase 内所有 bean 用 bootstrapExecutor 并发启动,CompletableFuture.allOf(...).get(timeout) 等待,超时则抛 ApplicationContextException。

LifecycleGroup.stop(第 633-666 行)用 CountDownLatch 等待 SmartLifecycle.stop(Runnable) 的回调,每个 phase 有独立的超时(默认 10 秒,第 124 行 timeoutPerShutdownPhase=10000),超时后只打 info 日志继续,不会卡死关闭流程。

3.11.4 getLifecycleBeans 的特殊逻辑

getLifecycleBeans(第 528-546 行)有一个细节:它会强制实例化所有 SmartLifecycle bean(即使是懒加载的):

Object bean = beanFactory.getBean(beanNameToCheck);

因为 SmartLifecycle 的 isAutoStartup 决定了它必须在容器启动时被 start,不管它是不是 @Lazy。而普通 Lifecycle bean 只有在已经是单例的情况下才被纳入(第 536 行 beanFactory.containsSingleton(beanNameToRegister))。这是一个容易踩的坑:SmartLifecycle 即使标了 @Lazy 也会被提前实例化。


4. 运行机制:从 refresh 到 destroy 的扩展点调用时间线

把前面分散在各节的调用位置串成一条完整时间线。以 AbstractApplicationContext.refresh()(第 581-661 行)为主轴,标注每一步触发了哪些扩展点:

4.1 refresh 阶段(启动)

步骤源码位置触发的扩展点
prepareRefresh()第 667 行无(只设置 active 标志、初始化 PropertySources)
obtainFreshBeanFactory()第 719 行无(刷新内部 beanFactory)
prepareBeanFactory()第 729 行注册 ApplicationContextAwareProcessor(BeanPostProcessor)、ApplicationListenerDetector、ignoreDependencyInterface 七项 Aware
postProcessBeanFactory()第 786 行子类扩展点(空实现,WebApplicationContext 在这里加 ServletContextAwareProcessor)
invokeBeanFactoryPostProcessors()第 794 行容器级扩展点总爆发:所有 BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry → 所有 BeanFactoryPostProcessor.postProcessBeanFactory;内部触发 ConfigurationClassPostProcessor → @Import → ImportSelector/DeferredImportSelector/ImportBeanDefinitionRegistrar
registerBeanPostProcessors()第 811 行把所有 BeanPostProcessor bean 实例化并按 PriorityOrdered/Ordered/无序三批注册进 beanFactory;最后补注册 internalPostProcessors 与 ApplicationListenerDetector
initMessageSource()第 820 行无(初始化 MessageSource bean)
initApplicationEventMulticaster()第 825 行附近无
onRefresh()第 906 行子类扩展点(如 WebServerApplicationContext 在这里创建 Web 容器)
registerListeners()第 914 行把 ApplicationListener bean 注册到多播器
finishBeanFactoryInitialization()第 942 行preInstantiateSingletons() 触发所有单例创建;每个 bean 创建过程中触发 InstantiationAwareBeanPostProcessor/SmartInstantiationAwareBeanPostProcessor/MergedBeanDefinitionPostProcessor/BeanPostProcessor/*Aware/InitializingBean;全部完成后触发 SmartInitializingSingleton.afterSingletonsInstantiated
finishRefresh()第 1002 行LifecycleProcessor.onRefresh() → SmartLifecycle.start() 按 phase 升序;发布 ContextRefreshedEvent

4.2 单个 bean 的扩展点调用顺序(以普通 singleton 为例)

以 AbstractAutowireCapableBeanFactory.doCreateBean(第 556-649 行)为主轴:

doCreateBean(beanName, mbd, args)
 │
 ├─ resolveBeforeInstantiation(beanName, mbd)         [在 createBean 里,doCreateBean 之前]
 │    └─ InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
 │         └─ 若返回非 null → 补调 postProcessAfterInitialization() → return(短路)
 │
 ├─ createBeanInstance(beanName, mbd, args)
 │    └─ SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors()  [选构造器]
 │
 ├─ applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)
 │    └─ MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
 │         [AutowiredAnnotationBeanPostProcessor 在这里缓存 @Autowired 元数据]
 │
 ├─ addSingletonFactory(beanName, () -> getEarlyBeanReference(...))
 │    └─ SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()  [循环依赖时]
 │
 ├─ populateBean(beanName, mbd, bw)
 │    ├─ InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
 │    ├─ autowireByName / autowireByType
 │    └─ InstantiationAwareBeanPostProcessor.postProcessProperties()
 │         [AutowiredAnnotationBeanPostProcessor 在这里做字段/方法注入]
 │
 ├─ initializeBean(beanName, bean, mbd)
 │    ├─ invokeAwareMethods()
 │    │    ├─ BeanNameAware.setBeanName()
 │    │    ├─ BeanClassLoaderAware.setBeanClassLoader()
 │    │    └─ BeanFactoryAware.setBeanFactory()
 │    ├─ applyBeanPostProcessorsBeforeInitialization()
 │    │    ├─ ApplicationContextAwareProcessor → Environment/EmbeddedValueResolver/ResourceLoader/
 │    │    │    ApplicationEventPublisher/MessageSource/ApplicationStartup/ApplicationContextAware
 │    │    └─ InitDestroyAnnotationBeanPostProcessor → @PostConstruct
 │    ├─ invokeInitMethods()
 │    │    ├─ InitializingBean.afterPropertiesSet()
 │    │    └─ custom init-method
 │    └─ applyBeanPostProcessorsAfterInitialization()
 │         └─ AbstractAutoProxyCreator → AOP 代理
 │
 └─ registerDisposableBeanIfNecessary()
      └─ 若需要销毁 → DisposableBeanAdapter 包装后存入 disposableBeans

4.3 close 阶段(关闭)

AbstractApplicationContext.doClose(第 1181 行起):

  1. publishEvent(new ContextClosedEvent(this))——先通知事件监听器;
  2. lifecycleProcessor.onClose()——DefaultLifecycleProcessor.stopBeans(false),按 phase 降序停所有 SmartLifecycle,CountDownLatch 等待每个 bean 的 stop(Runnable) 回调,超时默认 10 秒/phase;
  3. destroyBeans() → AbstractApplicationContext.destroyBeans(第 1245 行)→ beanFactory.destroySingletons();
  4. DefaultSingletonBeanRegistry.destroySingletons(第 693 行)逆序遍历 disposableBeans,每个 destroySingleton → destroyBean → DisposableBeanAdapter.destroy:
    • 先停依赖此 bean 的所有 dependent beans(递归 destroySingleton);
    • 然后 DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(如 @PreDestroy);
    • 然后 DisposableBean.destroy();
    • 然后自定义 destroy-method。

4.4 设计意图:为什么扩展点要分这么多层

把这套扩展点体系设计得这么"碎",不是因为 Spring 团队喜欢拆接口,而是因为不同扩展点能拿到的对象状态不同:

  • 在 BeanDefinition 阶段(BFPP/BDRPP):bean 还没 new,能改蓝图,不能碰实例;
  • 在实例化前(postProcessBeforeInstantiation):beanClass 有了,连对象都没有,只能决定"要不要短路";
  • 在合并定义阶段(postProcessMergedBeanDefinition):对象刚 new 出来,类型确定了,但属性还没填,适合做注解元数据缓存;
  • 在属性填充阶段(postProcessProperties):对象存在,属性正在填,适合做自定义注入;
  • 在初始化前(postProcessBeforeInitialization):属性填完了,Aware 已回调,适合做 @PostConstruct;
  • 在初始化后(postProcessAfterInitialization):afterPropertiesSet 都跑完了,对象完全就绪,适合做代理包装(AOP);
  • 在销毁前(postProcessBeforeDestruction):对象还在,即将被销毁,适合做 @PreDestroy。

每一层扩展点都精确对应一个"对象状态切片",用户只能在对应切片上做事,这就是 Spring 容器"可控"的根本原因——你不可能在 postProcessBeanFactory 里拿到一个已经注入完成的 bean,因为那个时机根本不存在。

5. 扩展用法与最佳实践

5.1 自定义 BeanPostProcessor:做通用日志/代理/延迟替换

最常见的扩展场景是写一个 BeanPostProcessor,对所有符合条件的 bean 做统一包装。下面是一个完整可运行的例子——给所有实现了 Auditable 接口的 bean 包一层日志代理:

public class AuditableBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (!(bean instanceof Auditable auditable)) {
			return bean;
		}
		// 已经被代理过就不再包
		if (AopUtils.isAopProxy(bean)) {
			return bean;
		}
		ProxyFactory pf = new ProxyFactory(bean);
		pf.addAdvice((MethodInterceptor) invocation -> {
			long start = System.currentTimeMillis();
			try {
				return invocation.proceed();
			} finally {
				System.out.println("[AUDIT] " + bean.getClass().getSimpleName() + "#"
						+ invocation.getMethod().getName() + " took "
						+ (System.currentTimeMillis() - start) + "ms");
			}
		});
		return pf.getProxy(bean.getClass().getClassLoader());
	}

	@Override
	public int getOrder() {
		return Ordered.LOWEST_PRECEDENCE;  // 最后执行,让 AOP 等其他后处理器先跑完
	}
}

注册方式(注意 static):

@Configuration
public class AppConfig {

	@Bean
	public static AuditableBeanPostProcessor auditableBeanPostProcessor() {
		return new AuditableBeanPostProcessor();
	}
}

几个要点:

  1. 必须 static:@Bean 方法返回 BeanPostProcessor 时必须 static,否则配置类本身会被提前初始化,导致配置类里其他 bean 不经过完整后处理器链(见 BeanPostProcessorChecker 的 warn 日志)。
  2. 重写 getOrder():如果你的后处理器需要在 AOP 之前/之后跑,用 PriorityOrdered 或 Ordered 指定顺序。一般做包装的后处理器放 LOWEST_PRECEDENCE(最后),让别人先包。
  3. 检查 AopUtils.isAopProxy(bean):避免重复包装。如果 bean 已经被 AbstractAutoProxyCreator 代理过,你再包一层会形成多层代理。
  4. 只在 postProcessAfterInitialization 做包装:因为此时 bean 已经完全初始化(afterPropertiesSet 都跑完了),代理拿到的是最终状态。在 postProcessBeforeInitialization 做代理会导致 @PostConstruct/afterPropertiesSet 作用在原始对象上而不是代理上,代理的 advice 拦截不到初始化方法。

5.2 自定义 BeanFactoryPostProcessor:修改 BeanDefinition 的典型场景

典型场景是"统一修改一批 bean 的属性值"。比如把所有 DataSource bean 的 url 从生产地址改成测试地址:

public class TestDataSourceUrlPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		for (String name : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition bd = beanFactory.getBeanDefinition(name);
			if (bd.hasAttribute("dataSource") || isDataSourceClass(bd)) {
				MutablePropertyValues pvs = bd.getPropertyValues();
				pvs.add("url", "jdbc:h2:mem:test");
				pvs.add("username", "sa");
			}
		}
	}

	private boolean isDataSourceClass(BeanDefinition bd) {
		try {
			return DataSource.class.isAssignableFrom(
					ClassUtils.forName(bd.getBeanClassName(), getClass().getClassLoader()));
		} catch (Throwable t) {
			return false;
		}
	}

	@Override
	public int getOrder() {
		return 0;  // PriorityOrdered,尽早跑
	}
}

关键约束:

  • 绝对不能在这里 getBean()。接口 javadoc 明确说这会导致 premature instantiation。如果你确实需要看某个 bean 的类型,用 getBeanNamesForType(只拿名字不实例化)或检查 BeanDefinition.getBeanClassName()。
  • 改的是 BeanDefinition 的 propertyValues,不是 bean 实例。等后面 populateBean 时这些新值才会被应用。
  • 如果你的 BFPP 需要替换 ${...} 占位符,要在 PropertySourcesPlaceholderConfigurer 之前还是之后跑?这取决于你的场景:占位符替换类 BFPP(如 PropertySourcesPlaceholderConfigurer 本身)通常实现 PriorityOrdered 且 order 值很小,先跑;业务自定义的 BFPP 一般无序,后跑。

5.3 用 ImportBeanDefinitionRegistrar 动态注册大量 bean

这是 starter 开发的核心模式。假设你要做一个 @EnableGrpcClients 注解,扫描所有 @GrpcClient 注解的接口,为每个接口注册一个 FactoryBean:

public class GrpcClientRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

	private BeanFactory beanFactory;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		// 1. 拿到 @EnableGrpcClients 的 basePackages
		AnnotationAttributes attrs = AnnotationAttributes.fromMap(
				metadata.getAnnotationAttributes(EnableGrpcClients.class.getName()));
		String[] basePackages = attrs.getStringArray("basePackages");

		// 2. 扫描这些包下带 @GrpcClient 的接口
		ClassPathScanningCandidateComponentProvider scanner =
				new ClassPathScanningCandidateComponentProvider(false);
		scanner.addIncludeFilter(new AnnotationTypeFilter(GrpcClient.class));

		for (String basePackage : basePackages) {
			for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
				String className = candidate.getBeanClassName();
				// 3. 为每个接口注册一个 GrpcClientFactoryBean
				RootBeanDefinition rbd = new RootBeanDefinition(GrpcClientFactoryBean.class);
				rbd.getConstructorArgumentValues().addGenericArgumentValue(className);
				rbd.setTargetType(ResolvType.forTypeName(className));
				String beanName = importBeanNameGenerator.generateBeanName(rbd, registry);
				registry.registerBeanDefinition(beanName, rbd);
			}
		}
	}
}

配套注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(GrpcClientRegistrar.class)
public @interface EnableGrpcClients {
	String[] basePackages() default {};
}

使用时 @EnableGrpcClients(basePackages = "com.example.client") 即可。@FeignClients、@MapperScan、@EnableJpaRepositories 都是这个模式。

5.4 注册顺序与依赖后处理器的注意点

  1. 后处理器之间不要互相 @Autowired。如果 BeanPostProcessor A 的构造器依赖了 BeanPostProcessor B,那 B 必须先实例化——但 B 的实例化又可能触发其他 bean 的创建,而那些 bean 还没被完整后处理链处理。BeanPostProcessorChecker 会打 warn。解决办法:后处理器之间的依赖尽量用 BeanFactoryAware 延迟拿,不要在构造器/字段里硬依赖。
  2. @Order 注解对后处理器无效。接口 javadoc 明确说:"Furthermore, the @Order annotation is not taken into account for BeanPostProcessor beans." 排序只能靠实现 PriorityOrdered/Ordered 接口并重写 getOrder()。
  3. 编程注册的后处理器不排序。ctx.addBeanFactoryPostProcessor(...) 或 ctx.addBeanPostProcessor(...) 严格按 add 顺序执行,实现 Ordered 也没用。
  4. BFPP 与 BPP 的先后:BFPP 在 invokeBeanFactoryPostProcessors 阶段全部跑完(包括实例化),BPP 在 registerBeanPostProcessors 阶段才实例化并注册。这意味着 BFPP 运行时,BPP 链还没建立——BFPP 自己产生的 bean 实例不会被 BPP 处理。这就是为什么 BFPP 不能在 postProcessBeanFactory 里 getBean() 的另一个原因:拿到的 bean 是"裸"的,没经过 AOP 等后处理。

5.5 自定义 SmartLifecycle 做优雅启停

public class MqConsumerLifecycle implements SmartLifecycle {

	private final Consumer consumer;
	private volatile boolean running;

	public MqConsumerLifecycle(Consumer consumer) {
		this.consumer = consumer;
	}

	@Override
	public void start() {
		consumer.start();
		this.running = true;
	}

	@Override
	public void stop(Runnable callback) {
		consumer.shutdown(() -> {
			this.running = false;
			callback.run();   // 必须调,否则 CountDownLatch 不会减
		});
	}

	@Override
	public boolean isRunning() { return running; }

	@Override
	public int getPhase() { return Integer.MAX_VALUE; }  // 最先停,最后启动
}

注意 stop(Runnable) 的 callback.run() 必须在真正停止完成后调用——DefaultLifecycleProcessor 的 CountDownLatch 靠这个回调减计数。忘了调会导致每个 phase 卡满 10 秒超时。getPhase() 返回 Integer.MAX_VALUE 意味着它在启动时最后启动、停止时最先停止——这是消息队列消费者的标准做法:先停消费者(不再接新消息),等业务 bean 处理完存量消息,最后停数据库。

6. 常见问题与坑

6.1 后处理器自身被后处理(死循环)的规避

问题场景:你写了一个 MyBeanPostProcessor implements BeanPostProcessor,它在 postProcessAfterInitialization 里做 AOP 代理。但 MyBeanPostProcessor 自己也是个 bean,它创建时也会被 postProcessAfterInitialization 回调——如果你的后处理器不做类型判断,就会给自己也包一层代理,而代理对象又触发一次后处理……

规避方法:在你的 postProcessAfterInitialization 开头加判断:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
	if (bean instanceof BeanPostProcessor) {
		return bean;   // 后处理器自己不被代理
	}
	// ... 正常代理逻辑
}

框架自带的 AbstractAutoProxyCreator 就是这么做的——它在 postProcessAfterInitialization 里检查 beanFactory 是否正在创建这个后处理器本身。更彻底的做法是用 BeanPostProcessorChecker 的 warn 日志来发现这类问题。

6.2 在 postProcessBeanFactory 中 getBean 的时机错误

典型错误代码:

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	Foo foo = beanFactory.getBean(Foo.class);   // ❌ 危险
	foo.doSomething();
}

后果:

  1. Foo 被提前实例化,此时 BeanPostProcessor 链还没注册(registerBeanPostProcessors 还没跑),Foo 不会经过 AOP、@Autowired 等处理——它可能是个"裸"对象;
  2. 如果 Foo 依赖了其他 bean,连锁触发更多 bean 的提前实例化,整个容器初始化顺序被打乱;
  3. 如果 Foo 是 FactoryBean,提前 getBean 会导致 factoryBeanObjectCache 被污染。

正确做法:在 postProcessBeanFactory 里只操作 BeanDefinition,不要碰 bean 实例。确实需要在容器启动后做初始化,用 SmartInitializingSingleton.afterSingletonsInstantiated 或 ContextRefreshedEvent 监听器。

6.3 postProcessBeforeInstantiation 返回非 null 跳过后续生命周期

前面源码已经分析过:一旦 postProcessBeforeInstantiation 返回非 null,doCreateBean 整个被跳过,包括 populateBean、initializeBean、invokeAwareMethods、InitializingBean.afterPropertiesSet。只有 postProcessAfterInitialization 会被补调一次。

这意味着:如果你写了一个 InstantiationAwareBeanPostProcessor 在 postProcessBeforeInstantiation 里返回了一个自定义对象,那么这个对象上的 @Autowired 字段不会被注入、@PostConstruct 不会被调、InitializingBean 不会触发。你必须在返回之前自己完成所有初始化——或者确保 postProcessAfterInitialization 里的其他后处理器能补回来。

AbstractAutoProxyCreator 是怎么处理这个的?它只在需要 TargetSource(如 LazyInitTargetSourceCreator)时才短路,且短路返回的代理对象自己实现了完整的延迟获取逻辑,不依赖容器的属性填充。

6.4 BeanPostProcessor 的并发与注册时机

7.0.9 支持并行实例化单例(通过 bootstrapExecutor)。此时多个线程同时创建不同 bean,每个线程都会触发 BeanPostProcessor.postProcessBefore/AfterInitialization。这要求:

  1. BeanPostProcessor 实现必须线程安全。它们是单例 bean,被所有创建线程共享。如果你在 postProcessProperties 里维护了一个 HashMap 做缓存,必须换成 ConcurrentHashMap(AutowiredAnnotationBeanPostProcessor.injectionMetadataCache 就是 ConcurrentHashMap)。
  2. 注册时机不能太晚。BeanPostProcessor 必须在 registerBeanPostProcessors 阶段(refresh() 第 605 行)全部注册完,之后才进入 finishBeanFactoryInitialization 创建普通单例。如果你在 refresh() 之后(比如运行时动态 addBeanPostProcessor),那它只对之后创建的 bean 生效,已经创建好的单例不会被 retroactive 处理。
  3. MergedBeanDefinitionPostProcessor 的并发安全:doCreateBean 里 applyMergedBeanDefinitionPostProcessors 用 synchronized (mbd.postProcessingLock) 保护,同一个 mbd 只处理一次。你的实现里如果有共享状态,要自己加锁。

6.5 @Bean 定义后处理器 vs 注解注册后处理器的差异

两种声明方式:

// 方式一:@Bean 方法
@Configuration
public class Config {
	@Bean
	public static MyBeanPostProcessor myBpp() { return new MyBeanPostProcessor(); }
}

// 方式二:@Component 扫描
@Component
public class MyBeanPostProcessor implements BeanPostProcessor { ... }

差异:

  1. @Bean 方式必须 static(前面说过),否则配置类提前初始化;
  2. @Component 方式:如果 MyBeanPostProcessor 本身被 @ComponentScan 扫到,它的 BeanDefinition 是在 ConfigurationClassPostProcessor(一个 BDRPP)阶段注册的。这意味着它在 invokeBeanFactoryPostProcessors 的 while 循环里被发现,然后在 registerBeanPostProcessors 阶段被实例化注册。顺序是正确的,但要注意:如果 MyBeanPostProcessor 依赖了某个在 @ComponentScan 之后才注册的 bean,可能会启动失败;
  3. 排序生效条件:两种方式都要实现 PriorityOrdered/Ordered 才能排序;
  4. @Bean 方式可以加参数:myBpp(SomeConfig config) 会注入 SomeConfig,但这会导致 SomeConfig 提前实例化——所以最好不要加参数,或只依赖基础设施 bean。

6.6 FactoryBean 产物不经过后处理器?

常见疑问:为什么我在 postProcessAfterInitialization 里没看到 FactoryBean.getObject() 返回的对象?

答案:会看到,但前提是 shouldPostProcess=true。在 FactoryBeanRegistrySupport.getObjectFromFactoryBean 里,单例 FactoryBean 的产物会走 postProcessObjectFromSingletonFactoryBean → postProcessObjectFromFactoryBean → applyBeanPostProcessorsAfterInitialization。但有两个例外:

  1. SmartFactoryBean 不缓存,每次 getObject() 都会调 postProcessObjectFromSingletonFactoryBean,所以每次都过后处理;
  2. containsSingleton(beanName) 为 false 时(第 160 行),产物不会被放进 factoryBeanObjectCache,但仍然会后处理;
  3. 循环依赖场景下的早期引用:如果 FactoryBean 正在创建中(isSingletonCurrentlyInCreation 为 true),postProcessObjectFromSingletonFactoryBean 第 229-231 行会临时返回未后处理的对象,不缓存——这是为了打破循环。等真正创建完成后,才会走完整后处理。

所以你的 BeanPostProcessor 要作用于 FactoryBean 产物,重写 postProcessAfterInitialization 即可,框架会自动调到。

6.7 其他高频坑

6.7.1 后处理器之间的顺序与 @Order 无效

如前所述,@Order 注解对 BeanPostProcessor 和 BeanFactoryPostProcessor 都无效。这是 7.0.9 源码里反复强调的一个事实(两个接口的 javadoc 都明确写了)。如果你习惯了用 @Order 排序 AOP advisor、事件监听器,到后处理器这里会发现失效。原因是:后处理器的排序在 PostProcessorRegistrationDelegate 里硬编码为"检查 isTypeMatch(ppName, PriorityOrdered.class) / isTypeMatch(ppName, Ordered.class)",它只看接口,不读注解。@Order 的解析发生在 OrderComparator 里,但 OrderComparator 对后处理器这种"需要提前实例化"的场景并不适用——因为注解解析需要类元数据,而此时还没实例化。

6.7.2 自定义 BeanPostProcessor 不生效的排查清单

如果你的自定义 BPP 没生效,按这个顺序查:

  1. 有没有被注册成 bean? 在 registerBeanPostProcessors 打日志,看 getBeanNamesForType(BeanPostProcessor.class) 里有没有你的类;
  2. 是不是 static @Bean? 如果是 @Bean 方法且非 static,配置类提前初始化会导致 BPP 自己不被完整处理;
  3. 有没有被 processedBeans 跳过? 如果你同时实现了 BeanDefinitionRegistryPostProcessor 和 BeanPostProcessor,它会被 registry 阶段"消费"掉,不会再走 BPP 注册流程;
  4. 是不是 synthetic bean? mbd.isSynthetic() 为 true 的 bean 不回调 BPP(见 doCreateBean 第 574、1416、1806 行的判断);
  5. 返回值是不是 null? applyBeanPostProcessorsBefore/AfterInitialization 里 null 会短路整条链。

6.7.3 SmartLifecycle 与 ContextRefreshedEvent 的选择

两者都是"容器就绪后"的钩子,但时机差了半步:

  • SmartInitializingSingleton.afterSingletonsInstantiated:所有单例创建完,但 lifecycle 还没 start、事件还没 publish;
  • SmartLifecycle.start()(由 onRefresh 触发):在 afterSingletonsInstantiated 之后,此时所有单例就绪;
  • ContextRefreshedEvent:在 finishRefresh 最后,onRefresh() 已经跑完,lifecycle 已经 start。

需要"容器完全就绪、lifecycle 已启动"再做事(如连接外部 MQ、启动定时任务),用 SmartLifecycle;只需要"所有 bean 都创建好了",用 SmartInitializingSingleton。

6.7.4 并行实例化下的扩展点注意事项

7.0.9 通过 bootstrapExecutor bean 支持单例并行实例化(DefaultListableBeanFactory.preInstantiateSingletons 第 1117-1134 行)。此时:

  • 不同 bean 在不同线程上并发创建,BeanPostProcessor 被并发调用——实现必须线程安全;
  • SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference 在三级缓存工厂里被调用,也可能在后台线程触发;
  • MergedBeanDefinitionPostProcessor 靠 mbd.postProcessingLock 保证只处理一次;
  • DefaultLifecycleProcessor 6.2.6 起支持按 phase 并发启动(setConcurrentStartupForPhase),需要配 bootstrapExecutor。

如果你的后处理器有共享可变状态(如缓存、计数器),一定要用并发容器或加锁,否则并行启动下会出诡异的并发问题。


7. 本章小结

7.1 扩展点体系总览

Spring Framework 7.0.9 的扩展点体系可以归纳为"三族十二接口":

容器级(改蓝图,任何实例化之前):

  • BeanFactoryPostProcessor:改 BeanDefinition 属性;
  • BeanDefinitionRegistryPostProcessor:注册新 BeanDefinition(先于普通 BFPP);
  • ImportSelector / DeferredImportSelector:按注解元数据返回要导入的配置类名;
  • ImportBeanDefinitionRegistrar:拿 registry 直接注册 BeanDefinition;
  • BeanFactoryInitializer:7.0 新增,在单例实例化前做一次性初始化。

Bean 级(改实例,单个 bean 创建过程中):

  • BeanPostProcessor:before/after 初始化两个钩子;
  • InstantiationAwareBeanPostProcessor:实例化前短路、实例化后、属性处理三个钩子;
  • SmartInstantiationAwareBeanPostProcessor:类型预测、构造器选择、早期引用暴露;
  • MergedBeanDefinitionPostProcessor:合并定义后回调(注解元数据收集挂载点);
  • DestructionAwareBeanPostProcessor:销毁前回调;
  • FactoryBean / SmartFactoryBean:自定义 bean 创建逻辑。

生命周期级(容器整体启停):

  • Lifecycle / Phased / SmartLifecycle:启停与排序;
  • InitializingBean / DisposableBean:单 bean 初始化与销毁;
  • *Aware 家族:把容器组件注入 bean;
  • SmartInitializingSingleton:所有单例就绪后的统一回调。

7.2 排序规则总结

所有扩展点的排序都遵循同一个三批模型:

  1. PriorityOrdered:第一批,按 getOrder() 升序;
  2. Ordered:第二批,按 getOrder() 升序;
  3. 无序:第三批,按 BeanDefinition 注册顺序。

批次之间严格先后,批次内部按 order 值。@Order 注解对后处理器无效;编程注册的后处理器不排序。

7.3 关键类清单

类名模块与相对路径职责一句话
BeanFactoryPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/BeanFactoryPostProcessor.java容器级后处理器接口,改 BeanDefinition
BeanDefinitionRegistryPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.java注册新 BeanDefinition 的容器级后处理器,先于 BFPP
PostProcessorRegistrationDelegatespring-context/src/main/java/org/springframework/context/support/PostProcessorRegistrationDelegate.javaBFPP/BPP 的实例化、排序、注册总编排
BeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/BeanPostProcessor.javaBean 级后处理器根接口,before/after 初始化
InstantiationAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/InstantiationAwareBeanPostProcessor.java实例化前短路/实例化后/属性处理三钩子
SmartInstantiationAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java类型预测/构造器选择/早期引用暴露
MergedBeanDefinitionPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/support/MergedBeanDefinitionPostProcessor.java合并定义后回调,注解元数据收集挂载点
DestructionAwareBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/config/DestructionAwareBeanPostProcessor.java销毁前回调与 requiresDestruction 判断
AbstractAutowireCapableBeanFactoryspring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.javadoCreateBean/initializeBean/populateBean,所有 Bean 级回调的触发点
ApplicationContextAwareProcessorspring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java回调 context 层 Aware(Environment/ApplicationContext 等)
AutowiredAnnotationBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java@Autowired/@Value 注入,实现 SmartInstantiationAware + MergedBeanDefinition
InitDestroyAnnotationBeanPostProcessorspring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java@PostConstruct/@PreDestroy 处理
ApplicationListenerDetectorspring-context/src/main/java/org/springframework/context/event/ApplicationListenerDetector.java检测内部 bean 是否为 ApplicationListener 并注册
ImportSelectorspring-context/src/main/java/org/springframework/context/annotation/ImportSelector.java按注解元数据返回要导入的类名
DeferredImportSelectorspring-context/src/main/java/org/springframework/context/annotation/DeferredImportSelector.java延迟到所有配置类处理完后执行,支持 Group 分组
ImportBeanDefinitionRegistrarspring-context/src/main/java/org/springframework/context/annotation/ImportBeanDefinitionRegistrar.java拿 BeanDefinitionRegistry 直接注册 bean
FactoryBeanspring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java自定义 bean 创建工厂
SmartFactoryBeanspring-beans/src/main/java/org/springframework/beans/factory/SmartFactoryBean.javaFactoryBean 扩展,支持 eagerInit 与按类型取对象
FactoryBeanRegistrySupportspring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.javaFactoryBean 产物缓存与后处理
SmartInitializingSingletonspring-beans/src/main/java/org/springframework/beans/factory/SmartInitializingSingleton.java所有单例就绪后的统一回调
DefaultListableBeanFactoryspring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.javapreInstantiateSingletons,单例预实例化与 SmartInitializingSingleton 触发
Lifecyclespring-context/src/main/java/org/springframework/context/Lifecycle.java基础启停接口
Phasedspring-context/src/main/java/org/springframework/context/Phased.javaphase 值排序接口
SmartLifecyclespring-context/src/main/java/org/springframework/context/SmartLifecycle.java自动启动+异步停止+phase 排序
LifecycleProcessorspring-context/src/main/java/org/springframework/context/LifecycleProcessor.javalifecycle bean 的启停编排 SPI
DefaultLifecycleProcessorspring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.javaLifecycleProcessor 默认实现,按 phase 分组启停
DisposableBeanAdapterspring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java销毁适配器,聚合 DestructionAwareBeanPostProcessor + DisposableBean + destroy-method
DefaultSingletonBeanRegistryspring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.javadisposableBeans 注册与逆序销毁

7.4 一句话总结

Spring 的扩展点体系本质上是一张"对象状态切片表":从 BeanDefinition 蓝图阶段,到实例化前、合并定义后、属性填充中、初始化前后、销毁前,再到容器整体的启停,每个状态切片都暴露一个精确的接口,让用户在不破坏容器两阶段契约(先改蓝图、再建实例、最后启停)的前提下,把自己的逻辑织进容器。理解了"每个扩展点在 refresh 十二步中的精确位置 + PriorityOrdered/Ordered/无序三批排序 + 后处理器自身也是 bean 这个双刃剑",就掌握了 Spring 容器扩展机制的全部精髓。