在此系列文章中,我总结了Spring几乎所有的扩展接口,以及各个扩展点的使用场景。并整理出一个bean在spring中从被加载到最终初始化的所有可扩展点的顺序调用图。这样,我们也可以看到bean是如何一步步加载到spring容器中的。
BeanFactoryPostProcessor
1、概述
BeanFactoryPostProcessor是Spring框架中的一个重要接口,用于在BeanFactory加载Bean定义之后、实例化Bean之前对BeanFactory进行自定义修改和扩展。它允许开发人员在Spring容器加载配置文件并创建Bean实例之前对Bean定义进行操作,例如修改属性值、添加额外的元数据等。
在应用程序启动时,Spring容器会自动检测并调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。开发人员可以利用这个方法来实现自定义的逻辑,从而实现一些高级的自定义逻辑和功能扩展。
前文介绍的BeanDefinitionRegistryPostProcessor为其子接口。
2、简单案例
下面是一个示例,展示了如何实现动态的给Bean修改属性值:
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的接口,最后是没有实现任何排序的接口):
@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的组件