BeanFactoryPostProcessor接口
BeanFactoryPostProcessor 接口允许我们在Spring容器加载Bean定义之后、Bean实例化之前修改这些Bean定义。它通常用于动态修改配置元数据(如XML配置文件或注解配置)。
org.springframework.beans.factory.config.BeanFactoryPostProcessor
/**
* Factory hook that allows for custom modification of an application context's
* bean definitions, adapting the bean property values of the context's underlying
* bean factory.
* Factory 钩子,允许自定义修改应用程序上下文的 bean 定义,调整上下文的基础 bean 工厂的 bean 属性值
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
*
* 在标准初始化后修改应用程序上下文的内部 Bean 工厂。
* 所有 bean 定义都已加载,但尚未实例化任何 bean。这允许覆盖或添加属性,甚至允许预先初始化 bean。
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
工作原理
当 Spring 容器加载配置文件(如 XML 配置文件或 Java 配置类)时,在所有 Bean 定义被加载后,会调用所有实现了 BeanFactoryPostProcessor 接口的类的postProcessBeanFactory方法。
这个方法接收一个ConfigurableBeanFactory类型的参数,通过这个参数可以访问和修改 Bean 工厂中的 Bean 定义。
使用场景
- 修改Bean定义属性。
- 修改Bean之间的依赖关系。
- 添加或移除某些Bean定义。
- 解析并处理自定义标签。
代码示例
可以自定义的 BeanFactoryPostProcessor 实现类,对Bean进行处理。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author qf
* @since 2024/10/16 19:58
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 获取名为user的Bean定义
if (beanFactory.containsBeanDefinition("user")) {
// 修改user的属性值
beanFactory.getBeanDefinition("user").getPropertyValues().add("id", 10001L);
}
// 拿到所有 bean 的名称
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
// 对每个Bean进行处理
System.out.println("对BeanDefinition: " + beanName +",进行处理");
}
}
}
User实体类
public class User {
private Long id;
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.qf.entity.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="1"></property>
</bean>
<bean class="com.qf.config.MyBeanFactoryPostProcessor"></bean>
<bean class="com.qf.config.MyBeanPostProcessor"></bean>
</beans>
测试类
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
System.out.println();
}
BeanPostProcessor接口
BeanPostProcessor 接口允许我们在Spring容器实例化Bean之后但在初始化前后对Bean进行处理。它可以在Bean对象实例化后对其进行增强或修改,例如设置额外的属性、包装Bean等。
org.springframework.beans.factory.config.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;
}
}
其中的两个方法
- postProcessBeforeInitialization:在Bean的初始化方法(如@PostConstruct或InitializingBean的afterPropertiesSet)调用之前执行。
- postProcessAfterInitialization:在Bean的初始化方法调用之后执行。
工作原理
对于 Spring 容器中的每个 Bean 实例化之后、初始化(调用init - method等)之前。
会先调用BeanPostProcessor接口的postProcessBeforeInitialization方法;
在 Bean 初始化之后,会调用postProcessAfterInitialization方法。这样就可以在 Bean 的生命周期的关键节点进行干预。
使用场景
- 在Bean初始化前后执行一些预处理和后处理操作。
- 包装或代理Bean,例如通过AOP实现切面编程。
- 设置Bean的额外属性或行为。
代码示例
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author qf
* @since 2024/10/16 19:58
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 在Bean初始化之前进行处理
if (beanName.equals("user")) {
System.out.println(beanName + "bean 初始化之前");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 在Bean初始化之后进行处理
if (beanName.equals("user")) {
System.out.println(beanName + "bean 初始化之后");
}
return bean;
}
}
两者在生命周期中的顺序
以下是Spring容器启动时的主要生命周期事件顺序:
- 读取配置文件或注解。
- 加载Bean定义。
- 调用 BeanFactoryPostProcessor.postProcessBeanFactory()。
- 创建Bean实例。
- 设置Bean属性。
- 调用 BeanPostProcessor.postProcessBeforeInitialization()。
- 调用Bean的初始化方法(如@PostConstruct或InitializingBean.afterPropertiesSet)。
- 调用 BeanPostProcessor.postProcessAfterInitialization()。
- 使用Bean。
- 销毁Bean(如果容器关闭)。
总结
两者的区别
- BeanFactoryPostProcessor:
- 在Bean定义加载之后但在Bean实例化之前工作。
- 主要用于修改Bean定义或解析自定义标签。
- 影响的是Bean定义层面,而不是具体的Bean实例。
- BeanFactoryPostProcessor操作的是BeanFactory(接口),主要是对 Bean 定义进行操作
- BeanPostProcessor:
- 在Bean实例化之后但在初始化前工作。
- 主要用于对已经实例化的Bean进行增强或修改。
- 影响的是具体的Bean实例,而不是Bean定义。
- BeanPostProcessor操作的是Bean(对象),是在 Bean 实例的生命周期阶段进行操作。
两者的联系
- 目的相同:
- 它们都是 Spring 框架提供的扩展点,用于对 Spring 容器的行为进行定制化。
- 无论是修改 Bean 定义还是在 Bean 生命周期阶段进行干预,都是为了满足应用在特定场景下的需求。
- 比如自定义配置加载、AOP(Aspect - Oriented - Programming)代理的创建等场景。
- 在 Spring 容器中的起到协同作用:
- 在 Spring 容器的启动和 Bean 的生命周期管理过程中,这两个接口的实现类会按照先后顺序协同工作。
- 首先是 BeanFactoryPostProcessor 对 Bean 定义进行调整,然后 Bean 实例化后,BeanPostProcessor 再对 Bean 实例进行处理。
- 两者共同完成对 Spring 容器内的 Bean 从定义到实例化、初始化的完整定制化过程。