Spring源码之BeanDefinitionRegistryPostProcessor内部执行流程

Spring提供了众多扩展接口,其中就有一个BeanDefinitionRegistryPostProcessor接口,它是BeanFactoryPostProcessor的一个子接口,该接口极其重要,因为在spring内部有一个类继承了该接口并且该类负责了包扫描的工作。在spring源码中是先处理实现了BeanDefinitionRegistryPostProcessor接口的类,下面我们来看下源码中是怎样处理的。

来到spring中最关键的初始化容器的refresh方法,找到invokeBeanFactoryPostProcessors这个方法,该方法就是负责处理BeanDefinitionRegistryPostProcessor(包扫描就是在这里处理的)以及其父类接口BeanFactoryPostProcessor。

一直点进去来到invokeBeanFactoryPostProcessors方法,可以发现这个方法有两个参数:

beanfactory就是spring的bean工厂对象,而第二个参数List<BeanFactoryPostProcessor>是什么尼?是从哪里传过来的?

在说这个参数之前,我们先说一下spring中3种Bean的管理添加方式:

  1. 手动通过api去添加到spring容器中
  2. 加上注解让spring能够包扫描到对应的类添加到容器中
  3. spring内部的类,spring源码中写好的添加到spring容器中

 第一种就是通过addXXX这样的api方式去手动添加Bean到spring容器中,这种方式比较少用,第二种是比较常用的加上@Component这些注解让spring通过包扫描到这些类加入到spring容器中,第三种就是spring内部源码写定了的一些Bean加入到spring容器中,例如说spring刚初始化的时候的有5个开天辟地的bd已经加入到了bdMap中。

说回上面那个参数,其实这个对象就是我们开发人员自己通过api传进来的对象,比如下面这样:

上面通过ApplicationContext对象去手动add一个继承了BeanDefinitionRegistryPostProcessor接口的类,这样该对象就会传到第二个参数中了,spring中首先先对手动add的类进行处理并且执行其相应的方法

一开始先创建了几个集合类,通过下面的代码逻辑可以知道这几个集合是什么作用的(如上图注释)。先遍历这个手动add的list集合,判断是BeanDefinitionRegistryPostProcessor还是BeanFactoryPostProcessor,如果是BeanDefinitionRegistryPostProcessor的话就执行它的postProcessBeanDefinitionRegistry方法。

下面就是分别对从bdMap中三次寻找为BeanDefinitionRegistryPostProcessor类的bd,并且每一次寻找到的类都会去执行其postProcessBeanDefinitionRegistry方法。

第一次从bdMap中寻找:

在此方法执行之前spring的bdMap中spring就已经手动地存放了5个bd,其中有一个极其重要的bd,该bd所描述的类(ConfigurationClassPostProcessor,这里不详细展开说这个类包扫描的细节)实现了BeanDefinitionRegistryPostProcessor这个接口,并且该类负责处理了包扫描的功能。所以第一次从bdMap中获取到的实现了BeanDefinitionRegistryPostProcessor这个接口的类的bd就是ConfigurationClassPostProcessor,执行该类重写的postProcessBeanDefinitionRegistry方法就能完成包扫描的过程(所谓的包扫描的过程就是把被@Component,@Controller,@Service,@Repository这些注解所标注的类变成对应的bd然后加入到bdMap中),当然了在扫描到的这些类之中也有可能有我们自己实现继承的BeanDefinitionRegistryPostProcessor这个接口的类,所以在第一次处理完这些BeanDefinitionRegistryPostProcessor类之后,bdMap都可能会发生变化,之后继续来到第二次寻找BeanDefinitionRegistryPostProcessor。

 第二次也是从bdMap中去寻找实现了BeanDefinitionRegistryPostProcessor接口的类对应的bd,然后遍历这些bd并且找到没有执行过的而且还实现了Ordered接口类的bd,继续去执行其重写的postProcessBeanDefinitionRegistry方法,也就是说不如在第一次包扫描完成了扫描到了我们自己实现继承的BeanDefinitionRegistryPostProcessor接口的类,此时bdMap中就会有我们这个类对应的bd,然后在第二次寻找的时候就会从bdMap中找到该类对应的bd,如果该类是实现了Ordered接口的话就能被执行postProcessBeanDefinitionRegistry方法。

在最后一次也就是第三次的寻找,就是在第二次寻找完之后的bdMap中继续去寻找,如果第二次寻找的时候bdMap继续有新的BeanDefinitionRegistryPostProcessor被添加进来,那么此时第三次寻找就会继续从bdMap中找到实现了BeanDefinitionRegistryPostProcessor接口的类对应的bd,while循环就是为了每寻找完一次之后继续去看bdMap是否还有实现了BeanDefinitionRegistryPostProcessor接口的类对应的bd。

 在经过了上面三次(第三次寻找中可能会有多次寻找)的寻找实现了BeanDefinitionRegistryPostProcessor的类的对应bd之后,此时的registryProcessors集合里面就是所有找到的实现了BeanDefinitionRegistryPostProcessor的实例了,执行invokeBeanFactoryPostProcessors此时就能把这些找到的实现了BeanDefinitionRegistryPostProcessor的实例的父类接口(BeanFactoryPostProcessor)的postProcessBeanFactory方法去执行了。而执行invokeBeanFactoryPostProcessors此时就能执行手动通过api添加的BeanFactoryPostProcessor的postProcessBeanFactory方法了。

最后,上面只是简单地通过源码去看BeanDefinitionRegistryPostProcessor的处理流程是怎样的,如果对spring管理bean的流程不太清楚的同学来说的话单看这篇文章可能稍微不太懂,需要知道什么是BeanDefinition(bd),以及spring是如何进行包扫描的。而为什么spring需要先处理BeanDefinitionRegistryPostProcessor这个后置处理器尼?因为这个后置处理器能暴露bdMap的访问入口,从而可以通过该后置处理器去手动地添加或者删除bdMap里面的bd,所以实现该接口的类(spring内部的ConfigurationClassPostProcessor)在包扫描之后把扫描到的类变成对应的bd,然后再把bd放入到bdMap中,所以先处理该接口类是管理所有Bean的一个入口

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值