再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的? (3)

再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的?

  原型类型的对象创建过程分两步:① 实例化(反射调构造方法),② 初始化(属性填充),和单例类型对象的创建过程是一样的

  依赖的处理是在初始化过程中进行的, loop 对象依赖 circle 属性,所以对 loop 对象的 circle 属性进行填充的时候,需要去 Spring 容器获取 circle 实例

  又来到了我们熟悉的 getBean ,获取 loop 依赖的 circle 实例,我们继续往下跟

再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的?

  在 circle 对象创建之前,同样调用了 beforePrototypeCreation 方法,那么此时 prototypesCurrentlyInCreation 中就同时存在 loop 和 circle 

  表示当前线程正在创建 loop 实例和 circle 实例;继续往下走

再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的?

  兜兜转转又来到了 getBean ,获取 circle 对象依赖的 loop 属性,接下来是重点,大家看仔细了

再探循环依赖 → Spring 是如何判定原型循环依赖和构造方法循环依赖的?

  因为 prototypesCurrentlyInCreation 中存在 loop 了,说明当前线程正在创建 loop 实例

  而现在又要创建新的 loop ,说明陷入死循环了,所以抛出了 BeanCurrentlyInCreationException 

总结

  经过上面的梳理,相信大家对之前的三个问题都没有疑问了,我们来总结下

  1、Spring 是如何甄别单例情况下的构造方法循环依赖的

    Spring 通过 Set<String> singletonsCurrentlyInCreation 记录当前正在创建中的实例名称

    创建实例对象之前,会判断 singletonsCurrentlyInCreation 中是否存在该实例的名称,如果存在则表示死循环了,那么抛出 BeanCurrentlyInCreationException 

  2、Spring 是如何甄别原型循环依赖的

    Spring 通过 ThreadLocal<Object> prototypesCurrentlyInCreation 记录当前线程正在创建中的原型实例名称

    创建原型实例之前,会判断 prototypesCurrentlyInCreation 中是否存在该实例的名称,如果存在则表示死循环了,那么抛出 BeanCurrentlyInCreationException 

  3、为什么单例构造方法循环依赖和原型循环依赖的报错时机不一致

    单例构造方法实例的创建是在 Spring 启动过程中完成的,而原型实例是在获取的时候创建的

    所以两者的循环依赖的报错时机不一致

参考

  Spring 的循环依赖,源码详细分析 → 真的非要三级缓存吗

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzzgy.html