• Spring注解驱动之BeanFactory的初始化


    概述

    经过前面的研究,我们发现IOC容器在创建对象的时候,会注册一些后置处理器,上一讲中已经把AnnotationAwareAspectJAutoProxyCreator后置处理器创建出来了,它是@EnableAspectJAutoProxy注解利用AspectJAutoProxyRegistrar给容器中创建出的一个bean。
    我们知道AnnotationAwareAspectJAutoProxyCreator是一个后置处理器,只有这个后置处理器已经创建出来并且放入容器中,那么以后在创建其他组件的时候,它就可以拦截到这些组件的创建过程了。因为创建任何bean实例时,都会经过bean的生命周期:创建bean,bean的属性赋值,初始化bean(在初始化bean前后都会有后置处理器的作用)等过程。
    注册完AnnotationAwareAspectJAutoProxyCreator后置处理器后,就是完成BeanFactory的初始化工作了。

    完成BeanFactory的初始化工作

    在这里插入图片描述
    注册完后置处理器之后,接下来就来到了finishBeanFactoryInitialization()方法处,以完成BeanFactory的初始化工作。所谓的完成BeanFactory的初始化工作,其实就是来创建剩下的单实例bean。为什么叫剩下的呢?因为IOC容器中的这些组件,比如一些BeanPostProcessor,早都已经在注册的时候就被创建了,所以会留一下没被创建的组件,让它们在这儿进行创建。

    完成BeanFactory的初始化工作的第一步

    遍历获取容器中所有的bean,并依次创建对象,注意是依次调用getBean()方法来创建对象的。
    在这里插入图片描述
    我们往前翻阅doGetBean()方法,就能看到已声明的sharedInstance变量了。
    在这里插入图片描述
    可以清楚地看到,在如下这行代码处是来第一次获取单实例bean。

    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    
    • 1
    • 2

    其实从注释中可以知道,它会提前先检查单实例的缓存中是不是已经人工注册了一些单实例的bean,若是则获取。

    完成BeanFactory的初始化工作的第二步

    也就是说,这个bean的创建不是说一下就创建好了的,它得先从缓存中获取当前bean,如果能获取到,说明当前bean之前是被创建过的,那么就直接使用,否则的话再创建。
    往上翻阅AbstractBeanFactory抽象类的doGetBean()方法,可以看到有这样的逻辑:
    在这里插入图片描述
    可以看到,单实例bean是能获取就获取,不能获取才创建。Spring就是利用这个机制来保证我们这些单实例bean只会被创建一次,也就是说只要创建好的bean都会被缓存起来。
    继续跟进方法调用栈,如下图所示,可以看到现在是定位到了DefaultSingletonBeanRegistry类的getSingleton()方法中。
    在这里插入图片描述
    这儿是调用单实例工厂来进行创建单实例bean。
    继续跟进方法调用栈,如下图所示,可以看到现在是定位到了AbstractAutowireCapableBeanFactory抽象类的createBean()方法中。
    在这里插入图片描述
    该方法是来解析BeforeInstantiation的。我们可以看一下该方法上的注释,它是说给后置处理器一个机会,来返回一个代理对象,替代我们创建的目标的bean实例。也就是说,我们希望后置处理器在此能返回一个代理对象,如果能返回代理对象那当然就很好了,直接使用就得了,如果不能那么就得调用doCreateBean()方法来创建一个bean实例了。
    如下图所示,可以看到现在是定位到了AbstractAutowireCapableBeanFactory抽象类的resolveBeforeInstantiation()方法中,既然程序是停留在了此处,那说明并没有走后面调用doCreateBean()方法创建bean实例的流程,而是先来到这儿,希望后置处理器能返回一个代理对象。
    在这里插入图片描述

    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    if (bean != null) {
        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    }
    
    • 1
    • 2
    • 3
    • 4

    这一块会调用两个方法,一个叫方法叫applyBeanPostProcessorsBeforeInstantiation,另一个方法叫applyBeanPostProcessorsAfterInitialization。
    调用applyBeanPostProcessorsBeforeInstantiation()方法返回一个对象的,那这个方法是干啥的呢?我们继续跟进方法调用栈,如下图所示,可以看到现在是定位到了AbstractAutowireCapableBeanFactory抽象类的applyBeanPostProcessorsBeforeInstantiation()方法中。
    在这里插入图片描述
    我们发现,它是拿到所有的后置处理器,如果后置处理器是InstantiationAwareBeanPostProcessor这种类型的,那么就执行该后置处理器的postProcessBeforeInstantiation()方法。我为什么要说这个方法呢?因为现在遍历拿到的后置处理器是AnnotationAwareAspectJAutoProxyCreator这种类型的,如下图所示。
    在这里插入图片描述
    它就是InstantiationAwareBeanPostProcessor这种类型的后置处理器,这种类型的后置处理器中声明的方法就叫postProcessBeforeInstantiation,而不是我们以前学的后置处理器中的叫postProcessbeforeInitialization的方法,也就是说后置处理器跟后置处理器是不一样的。
    我们以前就知道,BeanPostProcessor是在bean对象创建完成初始化前后调用的。而在这儿我们也看到了,首先是会有一个判断,即判断后置处理器是不是InstantiationAwareBeanPostProcessor这种类型的,然后再尝试用后置处理器返回对象(当然了,是在创建bean实例之前)。
    总之,我们可以得出一个结论:AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前,先尝试返回bean的实例。
    最后,我们继续跟进方法调用栈,如下图所示,可以看到终于又定位到了AbstractAutoProxyCreator抽象类的postProcessBeforeInstantiation()方法中。
    在这里插入图片描述
    判断后置处理器是不是InstantiationAwareBeanPostProcessor这种类型时,轮到了AnnotationAwareAspectJAutoProxyCreator这个后置处理器,而它正好是InstantiationAwareBeanPostProcessor这种类型的,所以程序自然就会来到它的postProcessBeforeInstantiation()方法中。
    我们现在是终于分析到了AnnotationAwareAspectJAutoProxyCreator这个后置处理器的postProcessBeforeInstantiation()方法中,也就是知道了程序是怎么到这儿来的。
    最终,我们得出这样一个结论:AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前,会有一个拦截,因为它是InstantiationAwareBeanPostProcessor这种类型的后置处理器,然后会调用它的postProcessBeforeInstantiation()方法。

    参考

    Spring注解驱动开发第29讲——注册完AnnotationAwareAspectJAutoProxyCreator后置处理器之后,就得完成BeanFactory的初始化工作了

  • 相关阅读:
    CTFHub | 弱口令
    windows命令行查看和终止进程
    [Lua][Love] "图块集与地图" 加载显示功能 TileMap
    【AI开发:音频】二、GPT-SoVITS使用方法和过程中出现的问题(GPU版)
    电商接口api数据比价接口推荐
    kubernetes学习笔记-集群管访问理篇
    深入探究 C++ 编程中的资源泄漏问题
    乘积数量(冬季每日一题 14)
    Vue3.0 项目启动(打造企业级音乐App)
    《MongoDB入门教程》第19篇 文档更新之$rename操作符
  • 原文地址:https://blog.csdn.net/tianzhonghaoqing/article/details/126818722