文章目录


一、前言


概要:这个接口的作用:注册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接口亮相_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接口亮相_sed_04

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

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

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

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

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

注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_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接口亮相_spring_06

为了搞清楚这个问题,我们应该看看当前beanFactory的继承和实现,以springboot中的应用为例,当前beanFactory的类型是DefaultListableBeanFactory,来看看它的类图:

注册bean到spring容器,BeanDefinitionRegistryPostProcessor接口亮相_sed_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接口完成

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