美文网首页开源框架-Spring系列
一图看懂 Spring Bean 生命周期 原理

一图看懂 Spring Bean 生命周期 原理

作者: 云中人山 | 来源:发表于2020-10-12 16:21 被阅读0次

    网上搜的Spring 生命周期,大部分都是写个demo,然后说按顺序输出就完事了
    但是并没看到文章提起其位置,估计是这个问题太浅显了

    我debug了一下 Spring 核心的onRefresh方法,结合以前的一些猜测,大致确认ConfigurableListableBeanFactory#createBean是Bean创建的入口

    具体的生命周期的流转如下图所示

    Spring Bean生命周期 单例.png

    其实大家也可以参照网上的那些文章,直接打断点看堆栈,就可以得到具体的执行位置

    Spring中的循环依赖

    循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。
    在这里先解释一下,Spring中用了三层缓寸来处理循环依赖

    • 1级 singletonFactories : 单例对象的cache
    • 2级 earlySingletonObjects :提前暴露的单例对象的Cache
    • 3级 singletonFactories : 单例对象工厂的cache
      Spring会根据1->3的顺序进行Bean的获取

    在上图的 populateBean方法前,其实有如下一段代码判断是否存在循环依赖

    // 若 RootBeanDefinition 是 单例 且 允许容器尝试解决循环依赖问题 
    // 且 singletonsCurrentlyInCreation的map中包含当前的BeanName
    boolean earlySingletonExposure = mbd.isSingleton() 
    && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
             // 如果需要提前暴露
            if (earlySingletonExposure) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Eagerly caching bean '" + beanName 
    + "' to allow for resolving potential circular references");
                }
                // 将其加入第三级缓存
                this.addSingletonFactory(beanName, () -> {
                    return this.getEarlyBeanReference(beanName, mbd, bean);
                });
            }
    
            Object exposedObject = bean;
    

    让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。——来源博客

    后续还有一次循环依赖检查,检查提前暴露的对象是否被动态代理等修改为新的对象,如果有则报错
    这里有篇文章可以参考
    传送门

    相关文章

      网友评论

        本文标题:一图看懂 Spring Bean 生命周期 原理

        本文链接:https://www.haomeiwen.com/subject/thxppktx.html