spring_10_IOC容器的刷新过程_07

Spring_10_IOC容器的刷新过程_07

在上一篇文章中我们完成了对SpringIOC容器的第五大步骤的讲解,接下来我们来继续探索第六大步骤:注册所有Bean的后置处理:registerBeanPostProcessors(beanFactory);

在该方法上的注释说明:注册拦截bean的创建的Bean处理器。

接下来我们进入断点,一探究竟。

我们看到该方法中仍然是调用的代理类的静态方法来注册的所有Bean的后置处理器,我们先来看一下第六步骤的方法上面的注释:

实例化并且注册所有的Bean的后置处理器,如果这些后置处理器显示的给定了顺序,那么按照指定的顺序进行执行,值得注意的是必须在容器的bean进行实例化之前来执行该回调。

那么此时我们就应该知道BeanPostProcessor它的执行时机:在所有Bean的实例化之前执行回调。

我们现在在进入方法体之气再来总览一下看这个代理为我们做的事情:和执行Bean工厂的后置处理器逻辑结构是一样的。

我们简单说明一下即可。

底层调用的方法:

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)

进入方法体我们再一次的看到了一个WARNING,而且这个警告是和刚刚提到的执行Bean工厂的后置处理器的提示也是一模一样的,接下来通过BeanPostProcessor类型来获取所有属于这个类型的bean的名字,返回来的也是beanNames数组,该数组中包含我们配置进去的所有的BeanPostProcessor的bean的名称。

再往下我们看见beanFactory手动添加了一个Bean后置处理器BeanPostProcessorChecker(bean后置处理器检查器),这个检查器的构造函数中传递了两个参数,一个是当前的bean工厂,另外一个是将当前bean工厂中所有的bean后置处理器的数量(当前bean工厂中已有的和我们刚刚根据类型从配置文件中拿到的数量相加得到的总数)+1作为参数传递了进去,我们来看这个检查器是干什么的:大概的意思就是当一个Bean在BeanPostProcessor的实例化期间被创建时即当一个Bean它没有资格被所有的bean后置处理器所处理的时候,会有一条info级别的消息提示出来,那么为什么会没有资格这个条件就是在检查器中进行判断的。

怎么进行判断的:

在bean后置处理器的执行流程中如果走到了这个检查器的postProcessAfterInitialization方法时,有以下几个条件的判断,如果都为true的时候,那么就说明当前的bean没有资格。
1、当前的bean不是BeanPostProcessor类型的
2、当前的bean不是基础的bean
3、当前bean工厂中所有的bean后置处理器的总数小于我们这个检查器对象创建时传入的数量

什么是基础bean?
如果这个bean的名称不为空并且当前工厂中维护的所有beanName包含了这个bean的name,可以通过当前的beanName获取到Bean的定义信息,并且当前bean的角色为后台bean。在这些条件下,bean为基础Bean

实际的应用我们会在后面的步骤发现它的身影。

接下来创建了四个集合对象

List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); //实现了PriorityOrdered排序接口
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();//内部的后置处理器
List<String> orderedPostProcessorNames = new ArrayList<>();//实现了ordered接口
List<String> nonOrderedPostProcessorNames = new ArrayList<>();//什么接口排接口都没实现的后置处理器

在往下的代码就没有什么神奇之处了,大部分都是一些**“体力活”**,疯狂的遍历刚刚获取到的所有后置处理器,判断属于哪个类型,就放在哪个类型对应的集合中去,并且对这些集合中的元素分别进行排序、注册的逻辑,但是值得注意的是这样的代码:

if (pp instanceof MergedBeanDefinitionPostProcessor) {
    //说明当前对象既实现了BeanPostProcessor接口,又实现了MergedBeanDefinitionPostProcessor接口
    // 因为这两个接口是有父子关系的,当你只实现 MergedBeanDefinitionPostProcessor接口的时候
	// 并且又重写了 BeanPostProcessor 里面的两个方法
    internalPostProcessors.add(pp);
}

我们只需要关注这行代码的执行时机就可以了。

我们来看以下注册的逻辑,毕竟和我们上一篇提到的执行Bean工厂所有后置处理器方法逻辑不一样,我们说一个就可以,因为所有实现排序接口和没实现排序接口的注册逻辑都是一样的。

/**
 * Register the given BeanPostProcessor beans.
 *
 * 注册给定的 BeanPostProcessor
 */
private static void registerBeanPostProcessors(
    ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

    if (beanFactory instanceof AbstractBeanFactory) {
        // Bulk addition is more efficient against our CopyOnWriteArrayList there
        // 批量添加比 CopyOnWriteArrayList更有效
        //批量添加
        ((AbstractBeanFactory) beanFactory).addBeanPostProcessors(postProcessors);
    }
    else {
        //挨个添加
        for (BeanPostProcessor postProcessor : postProcessors) {
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }
}

最后的最后,我们又再一次的向bean工厂中添加了一个应用容器监听器的探测器,在添加之前我们的bean工厂中其实已经有了这个探测器:

为什么要再一次的注册这个探测器呢?

我们看上面的注释:

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 重新注册 后置处理器以将内部的bean检测为ApplicationListeners,将其移动到处理器链的末尾,用于获取代理等。

在这个add方法内部,先将这个元素移除出去,再添加进去,因为是一个List集合,所以会再链的末尾。应用的场景我们在后续流程中会看到。

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    // 如果当前List中存在这个元素,那么将这个元素移除出去
    this.beanPostProcessors.remove(beanPostProcessor);
    // Add to end of list
    // 添加到list的末尾处。
    this.beanPostProcessors.add(beanPostProcessor);
}

最后,我们已经将第六步骤执行完毕,我们来看一下当前所有的BeanPostProcessor:

自此,我们IOC容器刷新的第六大步骤已经全部完成。篇幅较少的前提下是因为第五大步骤我们已经详细的分析过每一个实现了不通的排序接口的处理流程,所以大家再看这篇文章一知半解的情况下可以仔细阅读上篇文章+再自己debug一遍流程,这样流程就会很清晰了。

我们这篇文章中添加进去的一些BeanPostProcessor它的使用场景后续再分析的时候是肯定可以看见方法的执行时机的,大家敬请期待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值