Spring循环依赖面试问题
分类:
文章
•
2024-05-07 21:30:04
循环依赖
- 循环依赖、循环调用
- 循环依赖是针对成员变量---单例才可以解决setter方法循环依赖,多例是无法解决循环依赖
- 构造方法循环依赖----无法解决,只有将构造依赖改为setter方法依赖
- setter方法循环依赖---可以解决
- 循环调用是针对方法---无法解决的
- 结论:
- 循环调用就是A方法调用B方法,B方法调用A方法,这是一个闭环,是死循环,只能规避,无法解决
- 解决setter方法循环依赖
- A对象依赖B对象、B对象依赖A对象
- A对象创建(实例化)
- 在1和2之间需要做一个处理:会将刚创建的bean通过ObjectFactory进行暴露,并且将ObjectFactory放入三级缓存
- A对象属性填充
- A对象给B对象属性进行赋值,需要获取B对象的值getBean();
- B对象实例化
- B对象属性填充
- B对象给A对象属性进行赋值,需要获取A对象的值getBean();
- 直接从缓存中取出对应的A对象?
- B对象初始化
- A对象初始化
- getBean流程
- 先去缓存中获取对应的bean
- 先去一级缓存查找-----------------------------value:完全初始化完毕的bean实例
- 没有再去二级缓存查找-----------------------value:只完成bean实例化的bean的实例
- 没有再去三级缓存查找-----------------------value:ObjectFactory通过该缓存将只完成bean实例化和bean的实例提前暴露(不只是将bean的引用放入缓存中,还需要对该未初始化完成的bean进行一些BeanPostProcessor处理)
- 如果bean没有再进行创建,并且将创建之后的bean放入缓存中
- 为什么要有三个缓存?
- 主要是通过二级缓存和三级缓存在解决循环依赖的问题。其中二级缓存和三级缓存有互斥的
- 三级缓存和二级缓存的区别?
- 二级缓存只需要存储beanName和提前暴露的bean的实例的映射关系即可;
- 三级缓存不仅需要提前暴露的bean进行返回,还要对该bean做BeanPostProcessor后置处理;
- 三级缓存将暴露的bean处理完之后,将暴露的bean转移到二级缓存,同时删除三级缓存的数据;
- 三级缓存才是解决循环依赖的根本;
- 引用是可以传递的,提前暴露的bean和完全初始化成功的bean,其实是一个对象。