Spring的容器扩展机制三大基石
在spring的容器中正是因为BeanFactoryPostProcessor、BeanPostProcessor和BeanPostProcessorRegister这几个扩展类才使得Spring容器具有各种各样的扩展点。下面我们来一一介绍这三种类的作用是什么。
BeanPostProcessor
BeanPostProcessor 本身是一个接口,Spring 内置了众多非常重要的子接口和实现类,它们是 Spring 框架实现依赖注入(IoC)、自动装配(Auto-Wiring)、AOP、生命周期管理等核心功能的基石。正是有了BeanPostProcessor才使得上述这些功能得以实现。下面我们来看看BeanPostProcessor源码
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor只有两个方法分别是postProcessBeforeInitialization用来进行bean初始化的前置处理操作,postProcessAfterInitialization用来进行bean初始化的后置处理操作。而BeanPostProcessor则是有很多的实现类,那么这些不同的实现类则是实现不同的扩展机制,下面我们来列举几个直接BeanPostProcessor继承类
1. InstantiationAwareBeanPostProcessor
这是 最重要、最强大 的一个子接口。它扩展了 BeanPostProcessor,在 Bean 实例化(Instantiation) 和 属性填充(Population) 阶段提供了干预点。
核心方法:
-
postProcessBeforeInstantiation(Class<?> beanClass, String beanName)-
时机:在目标 Bean 实例化之前(即调用构造函数
new MyBean()之前)。 -
作用:如果此方法返回一个非 null 对象,Spring 容器会短路后续正常的 Bean 创建流程(跳过构造函数、属性填充等),直接使用返回的对象作为 Bean 实例。这是实现 AOP 代理等高级功能的关键入口。
-
典型应用:AOP 代理创建器可以在这里返回一个代理对象来替代目标对象。
-
-
postProcessAfterInstantiation(Object bean, String beanName)-
时机:在目标 Bean 实例化之后(构造函数已调用),但在属性填充(依赖注入)之前。
-
作用:如果方法返回
false,Spring 将跳过对该 Bean 的后续属性填充过程。可以用于完全自定义的属性设置逻辑。
-
-
postProcessProperties(PropertyValues pvs, Object bean, String beanName)-
时机:在属性填充(依赖注入)之前(如果
postProcessAfterInstantiation未返回false)。 -
作用:这是 执行依赖注入的核心方法。它可以对即将设置的属性值(
PropertyValues)进行修改或直接完成注入。 -
典型应用:
AutowiredAnnotationBeanPostProcessor就是通过重写此方法,来实现@Autowired和@Value注解的注入逻辑。
-
总结:这个接口提供了在“创建对象”和“给对象属性赋值”这两个最核心步骤进行干预的能力。
属性填充(Population)阶段的核心执行环节正是由
InstantiationAwareBeanPostProcessor.postProcessProperties()方法来完成的。
2. DestructionAwareBeanPostProcessor
此接口在 Bean 生命周期结束时提供干预点,用于处理自定义的销毁逻辑。
核心方法:
-
postProcessBeforeDestruction(Object bean, String beanName)-
时机:在 Bean 被销毁之前(即在调用
@PreDestroy、DisposableBean.destroy()或自定义的destroy-method之前)。 -
作用:执行自定义的销毁前逻辑,例如释放 Bean 持有的非 Spring 管理的资源。
-
典型应用:
CommonAnnotationBeanPostProcessor实现了此接口,用于处理@PreDestroy注解。它在这个方法中找到并执行标有@PreDestroy的方法。
-
3. MergedBeanDefinitionPostProcessor
这是一个专注于 优化性能 的子接口。它在 Bean 定义被处理时进行干预,主要用于缓存元数据。
核心方法:
-
postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)-
时机:在 Spring 处理并合并完 Bean 的定义(
BeanDefinition)之后,但在 Bean 实例化之前。 -
作用:允许对合并后的最终
BeanDefinition进行后处理。最常见的用途是查找并缓存注解元数据,以避免在后续真正进行依赖注入时反复进行耗时的反射操作。 -
典型应用:
AutowiredAnnotationBeanPostProcessor实现了此接口。它在此方法中扫描目标 Bean 的类,查找所有@Autowired、@Value等注解的字段和方法,并将这些“注入点”元数据缓存起来,极大提升了后续postProcessProperties阶段的执行效率。
-
在这个阶段,会扫描即将创建的 Bean 的 Class 对象。它会通过反射找出所有标注了 @Autowired、@Value、@Inject 的字段和方法,并将这些元数据封装成一个 InjectionMetadata 对象。这样将数据存储之后
BeanFactoryPostProcessor
作用时机: 在Bean定义(BeanDefinition) 被加载之后,但在Bean实例化之前。
操作目标: 它操作的是 BeanDefinition。BeanDefinition 是Spring容器内部用来描述一个Bean的元数据,它定义了Bean的类名、作用域、属性值、构造函数参数等。你可以把它想象成制造Bean的“蓝图”或“配方”。
功能: 允许我们读取、修改、甚至添加新的 BeanDefinition。它不能对Bean的实例进行任何操作,因为此时Bean还没有被创建。
常见应用场景:
-
属性占位符配置(PropertyPlaceholderConfigurer): 将
@Value("${jdbc.url}")中的${jdbc.url}替换为配置文件中的实际值。它修改的是Bean定义中的属性值。 -
自定义注解扫描与注册: 比如自己写一个处理器,扫描特定注解的类,然后动态地向容器中注册新的BeanDefinition。
BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor 的作用非常强大,它允许开发者在 Bean定义被加载之后、但尚未创建任何Bean实例之前,对Spring容器中的Bean定义进行最终的、编程式的干预和修改。
核心作用
BeanDefinitionRegistryPostProcessor 的主要作用是在Spring容器标准初始化完成后,进一步定制和修改应用程序上下文的Bean定义(BeanDefinition)注册表。
具体来说,它可以:
-
动态注册新的Bean定义:向容器中注册一个全新的、在原始配置(XML、注解)中不存在的Bean。
-
修改已注册的Bean定义:覆盖或调整任何已经通过配置解析好的Bean的属性(例如:修改类名、修改构造函数参数、修改属性值、修改作用域等)。
-
移除已注册的Bean定义:从容器中删除一个已经注册的Bean定义,阻止其被实例化。
为什么需要它?/ 典型应用场景
-
基于条件的Bean注册:
-
根据类路径上是否存在某个类、某个环境属性是否被设置等条件,来决定是否动态注册某个Bean。
-
经典案例:Spring Boot 的自动配置(Auto-configuration)就大量使用了这个接口。
@ConditionalOnClass等注解背后的逻辑,最终就是在BeanDefinitionRegistryPostProcessor的实现中判断条件并决定是否注册Bean。
-
-
编程式替代XML/注解配置:
-
当你觉得XML或注解配置不够灵活,需要更复杂的逻辑来生成Bean定义时,可以用代码来实现。
-
例如,从一个外部配置文件(如数据库)中读取一串列表,然后为列表中的每一项都动态注册一个Bean。
-
-
集成第三方框架:
-
许多框架需要向Spring容器中“注入”自己定义的Bean。
-
经典案例:
-
MyBatis-Spring:它的
MapperScannerConfigurer就是一个BeanDefinitionRegistryPostProcessor。它会扫描指定的包路径,找到所有的Mapper接口,然后为每一个接口都动态注册一个对应的MapperFactoryBean的定义到Spring容器中。这样你就能用@Autowired直接注入一个只有接口的Mapper了。 -
Spring注解扫描:
ConfigurationClassPostProcessor是Spring中最重要的一个BeanDefinitionRegistryPostProcessor。它负责处理@Configuration、@ComponentScan、@Bean、@Import等注解。正是它扫描了你的项目,找到了所有带@Component注解的类,并将它们注册为BeanDefinition。
-
-
| 特性 | BeanDefinitionRegistryPostProcessor |
普通的 BeanFactoryPostProcessor |
|---|---|---|
| 能力 | 更强大。可以增、删、改 BeanDefinition。 |
较弱。通常只能修改已存在的 BeanDefinition 的属性。 |
| 时机 | 更早。在所有 BeanFactoryPostProcessor 之前执行。 |
在其之后执行。 |
| 参数 | BeanDefinitionRegistry (注册表) |
ConfigurableListableBeanFactory (工厂) |
| 比喻 | 城市规划局,可以决定要建哪些楼(注册)、拆哪些楼(移除)、修改楼盘规划(修改)。 | 楼盘设计师,只能在已有的楼盘规划基础上,修改楼房的内部装修(属性)。 |
总结
| 特性 | BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|---|
| 操作目标 | Bean的定义 (BeanDefinition) |
Bean的实例 (Object) |
| 作用时机 | Bean实例化之前 | Bean实例化、依赖注入之后,初始化回调前后 |
| 功能 | 修改Bean的元数据、蓝图 | 增强、包装、检查Bean实例 |
| 比喻 | 修改汽车设计蓝图的人 | 给成品汽车改装、贴膜、质检的人 |
| 使用方式 | 开发者常用,需实现接口 | 开发者常用,需实现接口 |
了解了容器扩展的三大基石,下面我们结合基石再来看看bean的生命周期
第一阶段:容器启动阶段 (Container Startup)
这个阶段为整个 IOC 容器做准备,重点是处理 BeanDefinition。
1. 加载与解析 (Loading and Parsing)
-
Spring 容器(
ApplicationContext)启动。 -
根据配置(XML、Java Config、注解扫描),找到所有需要管理的类。
-
将这些类解析成内部的
BeanDefinition对象。BeanDefinition是 Bean 的“蓝图”,包含了 Bean 的类名、作用域、属性、构造函数参数等元数据。此时,这些信息都是“静态”的。
2. BeanFactoryPostProcessor 干预 (修改蓝图)
-
容器现在已经拥有了所有
BeanDefinition的注册表。 -
容器会找到所有实现了
BeanFactoryPostProcessor接口的 Bean(例如PropertySourcesPlaceholderConfigurer用于解析${}占位符)。 -
依次调用它们的
postProcessBeanFactory方法,并传入ConfigurableListableBeanFactory。 -
此时,这些处理器可以读取、修改、甚至添加/移除现有的
BeanDefinition。例如,将属性占位符替换为实际值,或者动态注册新的 Bean 定义。 -
作用:在 Bean 实例化之前,修改其定义(蓝图)。
3. BeanPostProcessor 的注册 (准备加工工具)
-
容器会实例化所有实现了
BeanPostProcessor接口的 Bean(以及它的子接口,如InstantiationAwareBeanPostProcessor)。它们会被优先初始化,因为后续普通 Bean 的创建需要它们。 -
所有这些
BeanPostProcessor实例都会被收集起来,注册到一个内部的注册中心——通常由BeanDefinitionRegistry或AbstractApplicationContext内部维护(其概念就是BeanPostProcessorRegistry)。 -
这个注册中心会对所有
BeanPostProcessor进行排序(根据PriorityOrdered,Ordered接口和顺序),形成一个有序的处理器链,以备后续调用。
第二阶段:单个 Bean 的生命周期阶段 (Individual Bean Lifecycle)
当容器启动完成,或者因为依赖关系需要获取一个 Bean 时,就会针对单个 Bean 触发以下创建和初始化流程。
1. 实例化 (Instantiation)
-
根据处理后的
BeanDefinition,通过构造函数(反射)来实例化一个对象。相当于new MyServiceImpl()。 -
关键扩展点:
-
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(): 在调用构造函数之前执行。可返回一个代理对象来“短路”后续流程。 -
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(): 在实例化之后、属性填充之前执行。可阻止默认的属性填充。
-
2. 属性填充 (Populating) - 依赖注入
-
为刚创建的对象设置属性和注入依赖(
@Autowired,@Value,@Resource)。 -
关键扩展点:
-
InstantiationAwareBeanPostProcessor.postProcessProperties(): 依赖注入的实际执行者。AutowiredAnnotationBeanPostProcessor就在此方法中完成@Autowired的注入。
-
3. Aware 接口回调 (Aware Interface Injection)
-
如果 Bean 实现了各种
Aware接口(如BeanNameAware,ApplicationContextAware),Spring 会回调相应的方法,将容器信息注入给 Bean。 -
本质:这一步是由一个特殊的
BeanPostProcessor——ApplicationContextAwareProcessor—— 在其postProcessBeforeInitialization方法中实现的。
4. 初始化前 (Before Initialization)
-
调用所有
BeanPostProcessor的postProcessBeforeInitialization方法。 -
容器会从内部的
BeanPostProcessorRegistry中取出那个有序的处理器链,依次调用每个处理器的方法。 -
典型应用:
CommonAnnotationBeanPostProcessor在此处执行@PostConstruct注解的方法。
5. 初始化 (Initialization)
-
执行 Bean 的初始化方法。
-
如果实现了
InitializingBean接口,调用afterPropertiesSet()方法。 -
调用自定义的
init-method(XML 或@Bean中指定)。
-
6. 初始化后 (After Initialization)
-
调用所有
BeanPostProcessor的postProcessAfterInitialization方法。 -
同样,从
BeanPostProcessorRegistry获取处理器链并依次调用。 -
最重要应用:Spring AOP 在此处创建代理对象。
AnnotationAwareAspectJAutoProxyCreator会检查当前 Bean,如果需要被切面环绕,就创建一个代理对象并返回,用它替代原始的目标 Bean。
7. 就绪与销毁 (Ready & Destruction)
-
此时,Bean 已经完全创建好,驻留在应用上下文中,可以被使用。
-
当容器关闭时,会遍历所有单例 Bean,执行销毁方法(
@PreDestroy,DisposableBean.destroy(), 自定义destroy-method)。
更多推荐


所有评论(0)