我们知道Spring只支持单例的循环依赖,循环依赖有二种方式,一种是setter方式,一种是构造器方式,举个例子
二个类互相依赖,这种方式就是Setter方式的注入循环依赖 然后编写个测试类
可以发现是成功的。 那么接下来我们试试构造器的方式
还是这二个类,但是注入方式改成构造器形式的了,但是这二个类依然还是 单例 然后我们继续在测试类中测试
既然报循环依赖的错误???这是为什么???Spring不是说单例是可以解决循环依赖的嘛?????
既然想知道为什么那还是要去看下源码??
首先我们要知道在那个步骤会发生循环依赖。肯定是在类实例话的时候,因为实例化类的时候是需要注入属性的。所以我们直接进入到AbstractAutowireCapaableBeanFactory类的doCreateBean方法中,
红色箭头指向的这个方法就是实例化Bean的方法,它有三种方式实例化Bean,一种通过Bean工厂,一种有参数的构造器,一种是无参的构造器。
如果我们的单例子是以Setter方式循环注入的,那么在这里bean通过无参的构造器实例化之后,那么得到的Bean还是没有任何属性的Bean,接下来会一直执行下面这个方法
我们看下这个方法的源码
这个方法做了什么呢???我相信如果去百度Spring是如何解决循环依赖的那么得到的答案肯定是Spring在类未实例化完全之前(就是还没有进行属性赋值)就把创建这个Bean的ObjectFactory暴露出去。然后供其他类调用。所以这个方法的功能就是做这个的。Spring会将创建这个Bean的Objectfactory保存到缓存中去,也就是doGetBean方法的getSingleton()方法中的三级缓存中的第三层。
在将ObjectFactory暴露出去之后,Spring然后再进行属性注入,也就是populateBean方法,所以在注入属性的时候如果出现循环依赖,那么我们就可以通过暴露出去的ObjectFactory.getObject()获取实例,也就不会发生循环依赖的错误了。这就是为什么Setter方式的循环依赖注入不会报错的原因。
说完了Setter方式现在来说说构造器的循环注入,经过上面分析我们知道实例化一个完全的Bean在这个方法的步骤是:
1:通过构造器实例化(或者工厂方式,构造器有无参和有参二种方式)
2:将创建的Bean的Objectfactory暴露出去,也就是放到缓存中去
3:属性的赋值
在我们的这个例子中,如果通过构造器来进行循环依赖注入,那么在第一步的时候当我们要实例化BoyFriend这个类的时候就需要GirlFriend这个实例,但是在此之前我们还没有将创建bean的ObjectFactory暴露出去,BoyFriend根本就获取不到GirlFriend这个类的实例,哪怕是最原始的Bean。所以就会报循环依赖的错误了。这也就是为什么在Spring中单例只支持Setter方式的循环依赖注入方式。