Spring扩展接口(3):BeanFactoryPostProcessor

在此系列文章中,我总结了Spring几乎所有的扩展接口,以及各个扩展点的使用场景。并整理出一个bean在spring中从被加载到最终初始化的所有可扩展点的顺序调用图。这样,我们也可以看到bean是如何一步步加载到spring容器中的。


BeanFactoryPostProcessor

1、概述

java 复制代码
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

BeanFactoryPostProcessor是Spring框架中的一个重要接口,用于在BeanFactory加载Bean定义之后、实例化Bean之前对BeanFactory进行自定义修改和扩展。它允许开发人员在Spring容器加载配置文件并创建Bean实例之前对Bean定义进行操作,例如修改属性值、添加额外的元数据等。

在应用程序启动时,Spring容器会自动检测并调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。开发人员可以利用这个方法来实现自定义的逻辑,从而实现一些高级的自定义逻辑和功能扩展。

前文介绍的BeanDefinitionRegistryPostProcessor为其子接口。

2、简单案例

下面是一个示例,展示了如何实现动态的给Bean修改属性值:

java 复制代码
public class User {
    String name;
    String password;
}

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
        if (Objects.nonNull(beanDefinition)) {
            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
            propertyValues.addPropertyValue("name", "张三");
            propertyValues.addPropertyValue("password", "123456");
        }
    }
}

同样,若当容器中有多个BeanFactoryPostProcessor的时候,可以通过实现PriorityOrdered或Ordered接口来指定顺序(优先执行PriorityOrdered的接口,其次是Ordered的接口,最后是没有实现任何排序的接口):

java 复制代码
@Override
public int getOrder() {
   return 0; //值越小,优先级越高
}

3、源码分析

  • 在MyBeanFactoryPostProcessor打上断点,启动SpringApplication,可以看到左下角的调用链路。
  • spring的AbstractApplicationContext的refresh方法,执行this.invokeBeanFactoryPostProcessors(beanFactory)。
  • 接下来进入核心的invokeBeanFactoryPostProcessors方法,大概逻辑是先取出所有实现了BeanFactoryPostProcessor接口的类,在for循环中根据实现类的优先级放入不同的ArrayList()等待调用,先PriorityOrdered,再Ordered,最后调用无优先级的实现类。
  • 注意:BeanDefinitionRegistryPostProcessor也实现了BeanFactoryPostProcessor接口,所以postProcessorNames也包含BeanDefinitionRegistryPostProcessor实现类,它已先于BeanFactoryPostProcessor执行,所以在for循环中需要排除,见if (!processedBeans.contains(ppName))。
  • 最后,遍历调用BeanFactoryPostProcessor的组件