[面试题] BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、BeanPostProcessor 有什么区别?
📖 版块 A:知识讲解版 (温故知新)
-
BeanDefinitionRegistryPostProcessor:
- 继承自
BeanFactoryPostProcessor。 - 作用时机更早,发生在 BeanDefinition 注册阶段。
- 不仅能修改已有 BeanDefinition,还能继续向容器里注册新的 BeanDefinition。
- 典型实现:
ConfigurationClassPostProcessor。
- 继承自
-
BeanFactoryPostProcessor:
- 作用在 BeanDefinition 已经准备好、但 Bean 还未实例化的时候。
- 主要用于修改 BeanDefinition 元数据。
- 不能直接处理已经创建好的 Bean 实例。
-
BeanPostProcessor:
- 作用在 Bean 实例初始化前后。
- 主要用于增强或包装 Bean 实例。
- Spring AOP 的自动代理机制就是基于 BeanPostProcessor 实现的。
-
一句话区分:
BeanDefinitionRegistryPostProcessor处理“定义注册”。BeanFactoryPostProcessor处理“定义修改”。BeanPostProcessor处理“实例增强”。
🎤 版块 B:面试实战版 (高手逐字稿)
Q:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、BeanPostProcessor 有什么区别?
💬 高手逐字稿:
这三个接口名字很像,但它们作用的阶段完全不同。如果按 Spring 源码主线来看,我通常会把它们分成“定义阶段”和“实例阶段”两类。
第一类是 BeanDefinitionRegistryPostProcessor。它作用得最早,发生在 BeanDefinition 注册阶段。它不仅可以修改已有定义,甚至还能继续往容器里注册新的 BeanDefinition。也就是说,它的权力最大,因为这时候容器的“候选对象名单”本身都还可以变。最典型的实现就是 ConfigurationClassPostProcessor,Spring 的注解扫描和 @Bean 解析,核心就是靠它跑起来的。
第二类是 BeanFactoryPostProcessor。它也还作用在 BeanDefinition 阶段,但时机比上面稍晚一些。这个时候 BeanDefinition 基本已经都收集好了,它主要做的是“修改定义”,比如改属性、改作用域、补配置。但它处理的是元数据,不是实例对象。
第三类是 BeanPostProcessor。它已经不碰定义了,而是直接作用在 Bean 实例初始化前后。也就是说,当对象已经被 new 出来,准备初始化或者刚初始化完时,BeanPostProcessor 可以介入处理。Spring AOP 为什么能在不改业务代码的情况下把代理对象塞回容器,本质上就是因为自动代理创建器本身就是一个特殊的 BeanPostProcessor。
所以如果用一句话做区分:
- BeanDefinitionRegistryPostProcessor 决定“还能注册什么”;
- BeanFactoryPostProcessor 决定“定义要不要改”;
- BeanPostProcessor 决定“实例要不要增强”。
这三个接口加在一起,几乎把 Spring 容器从定义到实例的关键扩展点全部打通了。