在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)注册表。

具体来说,它可以:

  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 (工厂)
比喻城市规划局,可以决定要建哪些楼(注册)、拆哪些楼(移除)、修改楼盘规划(修改)。楼盘设计师,只能在已有的楼盘规划基础上,修改楼房的内部装修(属性)。

总结

特性BeanFactoryPostProcessorBeanPostProcessor
操作目标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)。

Logo

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

更多推荐