一、前言

概要:这个接口的作用:注册bean到spring容器(作用是学习的核心指导,要记住)
注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_其他
注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_其他_02

关于注册bean到容器
我们开发的类,如果想注册到spring容器,让spring来完成实例化,常用方式如下:

  1. xml中通过bean节点来配置;
  2. 使用@Service、@Controller、@Conponent等注解;
    其实,除了以上方式,spring还支持我们通过代码来将指定的类注册到spring容器中,也就是今天我们要实践的主要内容,接下来就从spring源码开始,先学习源码再动手实战;

本文两个要点

  1. 了解BeanDefinitionRegistryPostProcessor接口;
  2. 分析spring容器如何使用BeanDefinitionRegistryPostProcessor接口;
二、BeanDefinitionRegistryPostProcessor接口

实现注册bean功能的关键是BeanDefinitionRegistryPostProcessor接口,来看看这接口的继承关系,如下图:

注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_# (2)Spring框架_03

两个后置处理器接口的继承关系:
BeanFactoryPostProcessor是父接口;
BeanDefinitionRegistryPostProcessor是子接口。

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口(就是上一篇博客的接口),BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:

  1. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:该方法的实现中,主要用来对bean定义做一些改变,就是上一篇博客的方法

  2. void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力:

金手指:postProcessBeanFactory()和postProcessBeanDefinitionRegistry()区别
postProcessBeanFactory()方法:用来对bean定义做一些改变(上一篇博客核心);
postProcessBeanDefinitionRegistry()方法:用来注册更多的bean到spring容器中(本文核心);

注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_# (2)Spring框架_04

从上图可以看到,为了能让我们通过代码将bean注册到spring环境BeanDefinitionRegistry提供了丰富的方法来操作bean定义,判断、注册、反注册等方法都准备好了,我们在编写postProcessBeanDefinitionRegistry方法的内容时,就能直接使用入参registry的这些方法来完成判断和注册、反注册等操作;

三、本文核心:分析spring容器如何使用BeanDefinitionRegistryPostProcessor接口

来看看BeanDefinitionRegistryPostProcessor接口的实现类,是在哪里被spring容器使用的:

3.1 refresh()第五个方法:invokeBeanFactoryPostProcessors()方法

如下图所示,红框中的invokeBeanFactoryPostProcessors方法用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义:

注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_# (2)Spring框架_05

3.2 从AbstractApplicationContext类invokeBeanFactoryPostProcessors()方法到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法

打开invokeBeanFactoryPostProcessors方法,如下所示,实际操作是委托PostProcessorRegistrationDelegate去完成的:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    }

3.3 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法(重点,一共七个部分)

继续看PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法,该方法内容太丰富,我们只看重点,第一个重点如下图红框所示,当前的beanFactory是否实现了接口BeanDefinitionRegistry:
注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_# (2)Spring框架_06

为了搞清楚这个问题,我们应该看看当前beanFactory的继承和实现,以springboot中的应用为例,当前beanFactory的类型是DefaultListableBeanFactory,来看看它的类图:
注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_其他_07

从上图红框可见,beanFactory实现了BeanDefinitionRegistry接口,因此我们的关注点是if条件满足后的执行逻辑;

继续看PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors方法,以下片段就是操作BeanDefinitionRegistryPostProcessor的核心逻辑:

boolean reiterate = true;
while (reiterate) {
    reiterate = false;
    //查出所有实现了BeanDefinitionRegistryPostProcessor接口的bean名称
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        //前面的逻辑中,已经对实现了PriorityOrdered和Ordered的bean都处理过了,因此通过processedBeans过滤,processedBeans中没有的才会在此处理
        if (!processedBeans.contains(ppName)) {
            //根据名称和类型获取bean
            BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中
            registryPostProcessors.add(pp);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean的名称全部放在processedBeans中
            processedBeans.add(ppName);
            //执行此bean的postProcessBeanDefinitionRegistry方法
            pp.postProcessBeanDefinitionRegistry(registry);
            //改变退出while的条件
            reiterate = true;
        }
    }
}

//registryPostProcessors中保存了所有执行过postProcessBeanDefinitionRegistry方法的bean,
//现在再来执行这些bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
//regularPostProcessors中保存的是所有入参中带来的BeanFactoryPostProcessor实现类,并且这里面已经剔除了BeanDefinitionRegistryPostProcessor的实现类,
//现在要让这些bean执行postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

(1)所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,

(2)然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;

到这里,我们的源码学习部分就完成了。

四、面试金手指(面试语言组织)

金手指1:与【源码解析001 Spring启动初始化的关系】
refresh()中调用invokeBeanFactoryPostProcessors()方法,这是refresh()第5个方法:改变bean的定义(BeanFactoryPostProcessor接口).

金手指2:核心方法:PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法(重点,一共七个部分)
第一段到第五段:对仅仅实现了BeanDefinitionRegistryPostProcessor接口的处理;
第六段到第七段:对仅仅实现了BeanFactoryPostProcessor接口的处理;
合在一起,就是对仅实现了BeanDefinitionRegistryPostProcessor接口的处理、仅仅实现了BeanFactoryPostProcessor接口处理、同时实现了BeanDefinitionRegistryPostProcessor接口和BeanFactoryPostProcessor接口的处理;

金手指3:BeanDefinitionRegistryPostProcessor类两个方法
BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口(就是上一篇博客的接口),BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:

  1. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:该方法的实现中,主要用来对bean定义做一些改变,就是上一篇博客的方法
  2. void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:该方法用来注册更多的bean到spring容器中
五、小结

BeanDefinitionRegistryPostProcessor接口完成

天天打码,天天进步!!!