本文已参与「新人创作礼」活动,一起开启掘金创作之路。
循环依赖怎么产生?
简单来说,A依赖B,B依赖A
具体来说,spring中bean对象的创建都要经历实例化、属性赋值、初始化的过程
1.创建A对象时,实例化A对象,此时A对象中的b属性为空
2.从容器中查找B对象,如果找到了b就直接赋值,不存在循环依赖问题,找不到就要创建B对象
3.实例化B对象,此时B对象中的a属性为空,填充属性a
4.从容器中查找A对象,找不到a,需要创建a
Spring怎么解决循环依赖?
Spring内部通过三级缓存来解决循环依赖问题,三级缓存实际上是三个map结构的表,将不同状态的对象分开缓存,一级缓存由ConcurrentHashMap实现,存储初始化完成的成品对象,二级缓存由HashMap实现,存储属性赋值阶段的半成品对象,三级缓存由HashMap实现存储Bean的工厂。
三级缓存:
一级缓存:singletonObjects,ConcurrentHashMap实现,也叫单例池,存放初始化完成的成品对象.
二级缓存:earlySingletonObjects,使用HashMap实现,存放处于属性赋值阶段的半成品对象;
三级缓存:singletonFactories,使用HashMap实现,存放Bean的工厂,value值是一个工厂。
只有单例模式的Bean才能通过三级缓存来解决循环依赖的问题。
例如在A对象创建时:
- 对象A创建的属性赋值阶段需要B对象的引用,于是先将A的工厂放入第三级缓存,去实例化B
- B实例化的时候发现需要A对象,于是B先查一级缓存,没有A,再查二级缓存,还是没有A,就查三级缓存,找到A的工厂,从工厂获得A的引用,然后把引用存入二级缓存并删除三级缓存中的工厂。
- B顺利初始化后,将自己放到一级缓存中(此时B里面的A依然是创建中的状态),然后回来继续创建A,从一级缓存中拿到B,并完成A的创建,然后把A移动到一级缓存中。