本节主要记录BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的方法执行时机以及简单原理分析。

BeanFactoryPostProcessor

查看BeanFactoryPostProcessor源码:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图1

根据注释我们了解到postProcessBeanFactory方法的执行时机为:BeanFactory标准初始化之后,所有的Bean定义已经被加载,但Bean的实例还没被创建(不包括BeanFactoryPostProcessor类型)。该方法通常用于修改bean的定义,Bean的属性值等,甚至可以在此快速初始化Bean。

下面测试一波。

新建SpringBoot项目,Boot版本2.4.0,依赖如下:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter</artifactId>
  4. </dependency>

然后新建MyBeanFactoryPostProcessor,实现BeanFactoryPostProcessor接口:

  1. @Component
  2. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  3. private static final Logger logger = LoggerFactory.getLogger(MyBeanFactoryPostProcessor.class);
  4. public MyBeanFactoryPostProcessor() {
  5. logger.info("实例化MyBeanFactoryPostProcessor Bean");
  6. }
  7. @Override
  8. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  9. int beanDefinitionCount = beanFactory.getBeanDefinitionCount();
  10. logger.info("Bean定义个数: " + beanDefinitionCount);
  11. }
  12. @Component
  13. static class TestBean {
  14. public TestBean() {
  15. logger.info("实例化TestBean");
  16. }
  17. }
  18. }

在postProcessBeanFactory方法内,我们打印了当前已加载Bean定义的个数,并且在MyBeanFactoryPostProcessor类中,注册了TestBean。MyBeanFactoryPostProcessor和TestBean的构造函数输出的日志用于观察Bean实例化时机。

启动程序,输出如下:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图2

上面的日志证实了方法的执行时机的确是在BeanFactory标准初始化之后,所有的Bean定义已经被加载,但Bean的实例还没被创建(此时TestBean还未被实例化,日志还没有输出”实例化TestBean”,但这不包括BeanFactoryPostProcessor类型Bean,该方法执行之前,日志就已经输出了”实例化MyBeanFactoryPostProcessor Bean”)。

我们在postProcessBeanFactory方法上打个断点:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图3

以debug方式启动程序:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图4

通过追踪方法调用栈,我们可以总结出BeanFactoryPostProcessor的postProcessBeanFactory方法执行时机和原理:

  1. SpringApplication.run(MyApplication.class, args)启动Boot程序:
    深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图5
  2. run方法内部调用refreshContext方法刷新上下文:
    深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图6
  3. refresh方法内部调用invokeBeanFactoryPostProcessors方法:
    深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图7
  4. PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法内部:
    深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图8
    深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图9

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,新增了一个postProcessBeanDefinitionRegistry方法:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图10

通过注释我们了解到postProcessBeanDefinitionRegistry方法的执行时机为:所有的Bean定义即将被加载,但Bean的实例还没被创建时。也就是说,BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法执行时机先于BeanFactoryPostProcessor的postProcessBeanFactory方法。这个方法通常用于给IOC容器添加额外的组件。

举个例子测试一波。

新建BeanDefinitionRegistryPostProcessor的实现类MyBeanDefinitionRegistryPostProcessor:

  1. @Component
  2. public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
  3. private final Logger logger = LoggerFactory.getLogger(MyBeanDefinitionRegistryPostProcessor.class);
  4. @Override
  5. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  6. int beanDefinitionCount = registry.getBeanDefinitionCount();
  7. logger.info("Bean定义个数: " + beanDefinitionCount);
  8. // 添加一个新的Bean定义
  9. RootBeanDefinition definition = new RootBeanDefinition(Object.class);
  10. registry.registerBeanDefinition("hello", definition);
  11. }
  12. @Override
  13. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  14. }
  15. }

启动程序,输出如下:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图11

可以看到,BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法执行时机的确先于BeanFactoryPostProcessor的postProcessBeanFactory方法。

通过查看PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法源码也可以证实这一点:

深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor - 图12