一文看懂 BeanFactoryPostProcessor 与 BeanPostProcessor 接口


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容器启动时的主要生命周期事件顺序:

  1. 读取配置文件或注解。
  2. 加载Bean定义。
  3. 调用 BeanFactoryPostProcessor.postProcessBeanFactory()
  4. 创建Bean实例。
  5. 设置Bean属性。
  6. 调用 BeanPostProcessor.postProcessBeforeInitialization()
  7. 调用Bean的初始化方法(如@PostConstruct或InitializingBean.afterPropertiesSet)。
  8. 调用 BeanPostProcessor.postProcessAfterInitialization()
  9. 使用Bean。
  10. 销毁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 从定义到实例化、初始化的完整定制化过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值