深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor

导读:本篇文章讲解 深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

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

1. BeanFactoryPostProcessor

查看BeanFactoryPostProcessor源码:

@FunctionalInterface
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

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

下面测试一波,直接创建一个springboot项目即可。

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

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(MyBeanFactoryPostProcessor.class);

    public MyBeanFactoryPostProcessor() {
        logger.info("实例化MyBeanFactoryPostProcessor Bean");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        int beanDefinitionCount = beanFactory.getBeanDefinitionCount();
        logger.info("Bean定义个数: " + beanDefinitionCount);
    }

    @Component
    static class TestBean {
        public TestBean() {
            logger.info("实例化TestBean");
        }
    }
}

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

启动程序,输出如下:

image-20220501215256653

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

我们在postProcessBeanFactory方法上打个断点,以debug方式启动程序:

image-20220501215513146

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

image-20220501215946913

  1. SpringApplication.run(SpringDemoApplication.class, args)启动Boot程序:

    image-20220501215701534

  2. run方法内部调用refreshContext方法刷新上下文:

    image-20220501215742788

  3. refresh方法内部调用invokeBeanFactoryPostProcessors方法:

    image-20220501215826174

  4. PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法内部:

    这里直接调用了BeanFactoryPostProcessor的postProcessBeanFactory方法

    image-20220501220036917

2. BeanDefinitionRegistryPostProcessor

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

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;
}

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

举个例子测试一波。

新建BeanDefinitionRegistryPostProcessor的实现类MyBeanDefinitionRegistryPostProcessor:

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    private final Logger logger = LoggerFactory.getLogger(MyBeanDefinitionRegistryPostProcessor.class);

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        int beanDefinitionCount = registry.getBeanDefinitionCount();
        logger.info("Bean定义个数: " + beanDefinitionCount);
        // 添加一个新的Bean定义
        RootBeanDefinition definition = new RootBeanDefinition(Object.class);
        registry.registerBeanDefinition("hello", definition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

启动程序,输出如下:

image-20220501220345050

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16698.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!