循环依赖分三种: 构造器循环依赖, 属性注入循环依赖(单例), 属性注入循环依赖(原型). spring解决的是单例模式下的属性注入循环依赖.
核心类DefaultSingletonBeanRegistry下的三个Map(三级缓存):
- singletonObjects: 一级缓存,保存所有的singletonBean的实例,存储单例Bean名称->单例Bean实现映关系
- earlySingletonObjects: 二级缓存,保存所有早期创建的Bean对象,这个Bean还没有完成依赖注入,存储Bean名称->预加载Bean实现映射关系
- singletonFactories: 三级缓存,singletonBean的生产工厂,存储Bean名称->ObjectFactory实现映射关系
单例的设值注入Bean是如何解决循环依赖问题呢?假设循环注入是A-B-A:A依赖B(A中autowire了B),B又依赖A(B中又autowire了A).
关键就在于实例化和初始化是两个过程:
先实例化A,将A放入三级缓存singletonFactories中.
再开始初始化(填充属性)A,初始化过程中获取B实例,依次从一二三级缓存中获取,都没有B实例的缓存。
所以开始实例化B,同样将B放入三级缓存singletonFactories中,然后B开始初始化,从三级缓存中singletonFactories找到A,填充给B后再将A从三级缓存中删除放入二级缓存。
到此实例B初始化完成,并将自己放入一级缓存,A的初始化还没完成.
B实例化完成后填充给A,然后A实例从二级缓存中删除放入一级缓存。
其实一个缓存也能解决依赖问题,那为什么要设置成三成呢?首先要理解Spring生成Bean分为大致三步骤:初始化-设置-销毁, 在并发场景下,三个步骤都可能调用getBean()方法, 而单例模式下要保证只有一个实例, 那么Spring就是通过这些缓存和对象锁去解决这种问题的。