现在有这样两个类Class A和Class B,A需要注入B,B需要注入A,那么就出现了循环依赖,如果不解决这个循环依赖关系,就会出现套娃现象,在属性注入的时候出现死循环。在Spring中通过三级缓存,也就是三个map来解决这个问题的。
解决循环依赖的前提:
单例bean的循环依赖Spring才解决
依赖注入的方式不能全是构造器注入的方式
三级缓存:
- singletonObjects:一级缓存,完整的单例bean
- earlySingletonObjects:二级缓存,刚创建出来,还没做属性赋值的bean,半成品
- singletonFactories:三级缓存,用于创建bean的工厂
下面从源码上解读下Spring循环依赖的解决(下面是Spring在创建bean时候方法调用的一个UML图)
以上面的Bean A和Bean B为例:
- 在创建A的时候会调用AbstractBeanFactory#getBean,然后调用doGetBean()。
2.doGetBean方法内有几个比较核心的调用
- 第一个,创建(获取)bean时候,首先会先去三级缓存里查一下,是否已经有这个bean,如果有就直接返回了,调用DefaultSingletonBeanRegistry#getSingleton。第一次创建A肯定就没有了,所以返回null。
- 第二个,当从缓存里没有获取到bean,就要调用重载的getSingleton(String beanName, ObjectFactory<?> singletonFactory)
3.getSingleton(beanName,singletonFactory)方法调用
singletonFactory.getObject();会调用上面一步传入的函数表达式,最终会调用createBean方法,创建完整bean。最后会将返回的bean加入到一级缓存再返回。
加入到一级缓存
4.singletonFactory.getObject()方法,也就是createBean方法
AbstractAutowireCapableBeanFactory#createBean里面主要是调用了doCreateBean()
5.AbstractAutowireCapableBeanFactory#doCreadoteBean方法
doCreadoteBean方法主要干了几件事:
- 创建bean的实例,注意此时还没有做属性赋值
- 往三级缓存里田间bean的工厂 (在不考虑AOP情况下,此工厂就是放置上一步创建的没有设置属性的bean实例)
- 属性赋值(这里就会涉及到循环依赖,例如B在设置属性A的时候,这时候A又会取走一开始的getBean,在走到getSingleton(beanName)时候,这一次可以从三级缓存里拿到bean,不会return null,就不用又走下面createBean()的创建流程,而陷入死循环)
- bean最后的初始化
可以看到,在不考虑AOP情况下,三级缓存,其实就是把前面创建的bean返回了
6.populateBean做bean属性设置
获取A类bean走到populateBean()会去注入B,这个时候B会去走getBean()这个流程,又走到populateBean()方法,然后会去注入A,这个时候开始的第一个getSingleton方法,就直接能从缓存中拿到A实例,然后设置到B属性,就不会出现循环依赖。当B创建完成返回后,A卡在属性设置这里就能继续往下走,继续完成自己的初始化,最后返回。