通过实现 BeanFactoryPostProcessor 接口干预 Spring Bean 的注册
总结自:一文吃透 Spring Boot 扩展之 BeanFactoryPostProcessor 概述 BeanFactoryPost、Spring 的 BeanDefinitionRegistryPostProcessor 接口详解
什么是 BeanFactoryPostProcessor
BeanFactoryPostProcessor 是一个 Spring 提供的接口,是 Spring 中一个相当重要的扩展点,可用来对 Bean 注册进行修改扩展。
BeanFactoryPostProcessor,翻译过来即 Bean 工厂处理器。BeanFactoryPostProcessor 源码:
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
postProcessBeanFactory 方法执行时机:所有的 Bean 定义(BeanDefinition)已经被加载,但标准 Bean 的实例还没被创建时(不包括 BeanFactoryPostProcessor 类型)。该方法通常用于修改 Bean 的定义,Bean 的属性值等,甚至可以在此快速初始化 Bean。
另外一个相关的扩展接口的 BeanDefinitionRegistryPostProcessor,继承自 BeanFactoryPostProcessor,在 BeanFactoryPostProcessor 的基础上新增了一个方法:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
扩展的方法在所有的 Bean 定义即将被加载,但 Bean 的实例还没被创建时执行,也就是说,BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法执行时机先于 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。
区别于一个很类似的扩展接口 BeanPostProcessor,它的执行时机是在 Bean 初始化前后(此时 Bean 实例已经创建)。
小结一下,上面关联的扩展接口执行顺序如下:
-
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
-
BeanFactoryPostProcessor.postProcessBeanFactory
-
BeanPostProcessor.postProcessBeforeInitialization
-
BeanPostProcessor.postProcessAfterInitialization
如何使用 BeanFactoryPostProcessor
1、新建一个测试 Bean
@Data
@Component
public class Student {
@Value("${user.username:alvin}")
private String username;
@Value("${user.age:12}")
private int age;
}
注意 username 的默认值为 alvin。
2、新建处理器实现 BeanFactoryPostProcessor
@Component
@Slf4j
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.info("*** TestBeanFactoryPostProcessor#postProcessBeanFactory ***");
// 修改 Bean definition 属性信息
BeanDefinition userBeanDef = beanFactory.getBeanDefinition("student");
userBeanDef.getPropertyValues().add("username", "ming");
// 快速初始化 Bean
User user = (User) beanFactory.getBean("student");
log.info("student name: [{}]", user.getUsername());
}
}
3、验证结论
*** TestBeanFactoryPostProcessor#postProcessBeanFactory ***
student name: [ming]
从日志可以看到 Bean 的属性被修改了。
源码解析
接口说明
BeanDefinitionRegistryPostProcessor 接口的注释对它的作用和细节作了说明:
- 该接口允许用户自定义修改工厂 Bean 中的 BeanDefinition,调整 BeanDefinition 的属性值,甚至初始化 Bean。比如内置的 PropertyResourceConfigurer,实现该接口以修改 BeanDefinition 的属性为配置文件的属性。
- 该接口主要是用于修改 BeanDefinition,虽然也可以直接进行实例化 Bean,但是不建议这么做,可能会造成其他未知的错误。
postProcessBeanDefinitionRegistry 执行时机
AbstractApplicationContext#refresh 方法调用了 AbstractApplicationContext#invokeBeanFactoryPostProcessors:
![]() |
其进一步调用了 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors。该方法的前面部分逻辑主要是处理 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,后面部分主要处理 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法。
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 优先执行实现了 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor,其次就是实现了接口 Ordered 的,最后才是两者都没有实现的。
![]() |
调用 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法。
![]() |
postProcessBeanFactory 执行时机
跟 BeanDefinitionRegistryPostProcessor 的调用路径一样,在调用了所有的 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法后,紧接着就会处理所有的 BeanFactoryPostProcessor,按优先级调用其 postProcessBeanFactory 接口。
优先执行实现了 PriorityOrdered 接口的 BeanFactoryPostProcessor,其次就是实现了接口 Ordered 的,最后才是两者都没有实现的。
![]() |
![]() |
小结
整个执行流程的源码还是比较清晰并且简单的。重点提下下面两个点:
1、我们自定义的 BeanFactoryProcessor 需要加上 @Component 等注解,为什么?
看源码得知,String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);获取所有实现了 BeanFactoryPostProcessor 接口的 Bean 名称,前提所有的 Bean 都要被注册到 BeanDefinitionRegistry,通过添加 @Component,@Service 等注解,可以将对应的 Bean 定义信息注册到 BeanFactory 中,方便后面实例化 Bean。那么它是在什么地方注册的呢?可以看下 ConfigurationClassPostProcessor 类,它实现了 BeanDefinitionRegistryPostProcessor,会扫描所有 @Component,@Service 等注解,将对应的 Bean Definition 注册到 BeanFactory 中。
2、执行顺序问题
我们可以通过实现 PriorityOrdered,Ordered 接口,控制 BeanFactoryProcessor 的执行顺序,,优先执行实现了 PriorityOrdered 接口,其次是 Ordered,最后是没有实现任何排序接口的 processor。





浙公网安备 33010602011771号