bigywater.tech
Spring · 4

BeanPostProcessor 与 BeanFactoryPostProcessor:容器的两个扩展点

BeanPostProcessor 和 BeanFactoryPostProcessor 能做什么、会在哪里出问题?返回代理对象之后按具体类注入为什么失败?多个 BPP 谁先谁后?为什么 BPP 依赖的 Bean 会“不被所有 BPP 处理”?为什么 BFPP 的 @Bean 方法必须 static?这篇在 Spring Framework 7.0.9 上逐项验证。

第 5 / 6
没有顺序的两个 BPP 在 6 个 BPP 里的位置(PriorityOrdered 和 Ordered 之后)
2 个
Early 的构造器依赖被提前创建、后注册的 BPP 没有处理的 Bean 数(EarlyConf 与 service)
null
非 static 的 BFPP @Bean 方法被调用时,配置类里 @Autowired 字段的值

换掉对象

实测 · 本机执行输出
  ByIface 拿到:$Proxy10 调用结果 [包装]hi
  getBean("svc") 的类型:$Proxy10,是 SvcImpl 的实例?false
  异常 UnsatisfiedDependencyException ← BeanNotOfRequiredTypeException: Bean named 'svc' is expected to be of type 'demo.Main$SvcImpl' but was actually of type 'jdk.proxy2.$Proxy10'

BPP 返回的对象会替换原 Bean;返回 JDK 代理后,按具体类注入会失败。

执行顺序

实测 · 本机执行输出
  顺序:PriorityOrdered(5) → PriorityOrdered(10) → Ordered(0) → Ordered(1) → plain1(无顺序,最先注册) → plain2(无顺序,后注册)

PriorityOrdered、Ordered、无顺序三组,组内按 getOrder 升序,无顺序的按注册顺序。

过早创建

实测 · 本机执行输出
  LOG WARN PostProcessorRegistrationDelegate$BeanPostProcessorChecker: Bean 'main.EarlyConf' of type [demo.Main$EarlyConf$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying).…
  构造 Service
  LOG WARN PostProcessorRegistrationDelegate$BeanPostProcessorChecker: Bean 'service' of type [demo.Main$Service] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eag…
  构造 Early(BPP,构造器依赖 Service)
  Late(后注册的 BPP)看到了 plainBean

BPP 依赖的 Bean 在 BPP 注册阶段就被创建,后注册的 BPP 处理不到,Spring 打 WARN 提示。

BFPP 要 static

实测 · 本机执行输出
  LOG INFO ConfigurationClassEnhancer: @Bean method NonStatic.bfpp is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource, and…
  非 static 的 BFPP @Bean 方法被调用时,配置类里的 @Autowired Environment 字段 = null
  static 的 BFPP @Bean 方法被调用(静态方法不需要先创建配置类)
  配置类被创建后 @Autowired Environment 字段 = 已注入
  BFPP 要在其它 Bean 之前就拿到实例,非 static 的 @Bean 方法需要先创建它所在的配置类,这时 BeanPostProcessor 还没注册,@Autowired 之类的注解处理不了;所以 BFPP 和 BPP 的 @Bean 方法都应该写成 static

非 static 的 BFPP @Bean 方法需要先创建配置类,这时注解处理还没有就绪。

分步演示

BeanPostProcessor 与 BeanFactoryPostProcessor
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。用不带 Boot 的 Spring Framework 7.0.9;日志通过 logback.xml(INFO)输出,只摘录了 Spring 提示的几行,过长的行在末尾截断
    • 没有验证:用 CGLIB 代理(proxyTargetClass)替换 Bean 时按具体类注入是否成功(Spring AOP 的代理见后面的 AOP 篇);BeanDefinitionRegistryPostProcessor 的顺序;InstantiationAwareBeanPostProcessor 在 postProcessBeforeInstantiation 里直接返回对象的情形;Boot 里自带的 BPP 数量
    京ICP备2026067502号-1京公网安备11010502063487号