cat 的 RootBeanDefinition 中有几个属性值得我们注意下
接着往下走
我们来到了 createBeanInstance 方法,此时 Set<String> singletonsCurrentlyInCreation 只存放了 cat
singletonsCurrentlyInCreation 看字面意思就知道,存放的是当前正在创建中的单例对象名
我们接着往下跟
由于 constructorArgumentValues 中有元素,所以需要通过有参构造函数来创建 cat 对象
因为构造函数的参数是 Dog 类型的 dog ,所以通过反射调用 Cat 的有参构造函数来创建 cat 之前,需要先从 Spring 容器中获取到 dog 对象
获取 Cat 构造函数依赖的 dog 实例所以流程又来到了我们熟悉的 getBean ,只是现在获取的是 dog ;获取流程与获取 cat 时一样,所以跟的速度会快一些,大家注意看我停顿的地方
此时 singletonsCurrentlyInCreation 存放了 cat 和 dog ,表示他们都在创建中
又来到了 createBeanInstance ,过程与之前 cat 的过程一样,我们接着往下看
又来到了熟悉的 getBean ,需要从 Spring 容器获取 Dog 构造函数依赖的 cat 对象
获取 Dog 构造函数依赖的 cat 对象接下来重点来了,大家看清楚了
因为 singletonsCurrentlyInCreation 已经存在 cat 了, !this.singletonsCurrentlyInCreation.add(beanName) 结果就是 true
说明陷入死循环了,所以抛出了 BeanCurrentlyInCreationException
我们在控制台看到的异常信息就从这来的
原型循环依赖的甄别原型类型的实例有个特点:每次获取都会重新创建一个实例,那在 Spring 启动过程中,还有创建的必要吗?
Spring 启动不创建 prototype 类型的实例我们来跟下源码就明白了
关键代码
不符合上述 3 个条件的实例,在 Spring 启动过程中都不会被创建
下面接着讲正题,来看看 Spring 是如何甄别原型循环依赖的
获取 loop 实例
在 loop 实例创建之前,调用了 beforePrototypeCreation 方法,将 loop 名放到了 ThreadLocal<Object> prototypesCurrentlyInCreation
表示当前线程正在创建 loop ,我们接着往下看