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

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

   cat 的 RootBeanDefinition 中有几个属性值得我们注意下

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

  接着往下走

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

  我们来到了 createBeanInstance 方法,此时 Set<String> singletonsCurrentlyInCreation 只存放了 cat 

   singletonsCurrentlyInCreation 看字面意思就知道,存放的是当前正在创建中的单例对象名

  我们接着往下跟

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

  由于 constructorArgumentValues 中有元素,所以需要通过有参构造函数来创建 cat 对象

  因为构造函数的参数是 Dog 类型的 dog ,所以通过反射调用 Cat 的有参构造函数来创建 cat 之前,需要先从 Spring 容器中获取到 dog 对象

  获取 Cat 构造函数依赖的 dog 实例

  所以流程又来到了我们熟悉的 getBean ,只是现在获取的是 dog ;获取流程与获取 cat 时一样,所以跟的速度会快一些,大家注意看我停顿的地方

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

  此时 singletonsCurrentlyInCreation 存放了 cat 和 dog ,表示他们都在创建中

  又来到了 createBeanInstance ,过程与之前 cat 的过程一样,我们接着往下看

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

  又来到了熟悉的 getBean ,需要从 Spring 容器获取 Dog 构造函数依赖的 cat 对象

  获取 Dog 构造函数依赖的 cat 对象

  接下来重点来了,大家看清楚了

  因为 singletonsCurrentlyInCreation 已经存在 cat 了, !this.singletonsCurrentlyInCreation.add(beanName) 结果就是 true 

  说明陷入死循环了,所以抛出了 BeanCurrentlyInCreationException 

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

  我们在控制台看到的异常信息就从这来的

原型循环依赖的甄别

  原型类型的实例有个特点:每次获取都会重新创建一个实例,那在 Spring 启动过程中,还有创建的必要吗?

  Spring 启动不创建 prototype 类型的实例

  我们来跟下源码就明白了

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

  关键代码

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

  不符合上述 3 个条件的实例,在 Spring 启动过程中都不会被创建

  下面接着讲正题,来看看 Spring 是如何甄别原型循环依赖的

  获取 loop 实例

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

  在 loop 实例创建之前,调用了 beforePrototypeCreation 方法,将 loop 名放到了 ThreadLocal<Object> prototypesCurrentlyInCreation 

  表示当前线程正在创建 loop ,我们接着往下看

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

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