在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 被销毁之前(即在调用 @PreDestroyDisposableBean.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实例化之前。
操作目标: 它操作的是 BeanDefinitionBeanDefinition 是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)注册表。

具体来说,它可以:

  1. 动态注册新的Bean定义:向容器中注册一个全新的、在原始配置(XML、注解)中不存在的Bean。

  2. 修改已注册的Bean定义:覆盖或调整任何已经通过配置解析好的Bean的属性(例如:修改类名、修改构造函数参数、修改属性值、修改作用域等)。

  3. 移除已注册的Bean定义:从容器中删除一个已经注册的Bean定义,阻止其被实例化。

为什么需要它?/ 典型应用场景

  1. 基于条件的Bean注册

    • 根据类路径上是否存在某个类、某个环境属性是否被设置等条件,来决定是否动态注册某个Bean。

    • 经典案例:Spring Boot 的自动配置(Auto-configuration)就大量使用了这个接口。@ConditionalOnClass 等注解背后的逻辑,最终就是在 BeanDefinitionRegistryPostProcessor 的实现中判断条件并决定是否注册Bean。

  2. 编程式替代XML/注解配置

    • 当你觉得XML或注解配置不够灵活,需要更复杂的逻辑来生成Bean定义时,可以用代码来实现。

    • 例如,从一个外部配置文件(如数据库)中读取一串列表,然后为列表中的每一项都动态注册一个Bean。

  3. 集成第三方框架

    • 许多框架需要向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 进行排序(根据 PriorityOrderedOrdered 接口和顺序),形成一个有序的处理器链,以备后续调用。


第二阶段:单个 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 接口(如 BeanNameAwareApplicationContextAware),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,执行销毁方法(@PreDestroyDisposableBean.destroy(), 自定义 destroy-method)。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐