前言
当你觉得自己很疲惫的时候,别人也很疲惫,你没有理由不逼自己一把!这次说一下Spring中的循环依赖,纯手打+代码调试!及时总结。不然又忘记了!
** 1.什么是循环依赖?**
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。
项目结构:
Spring中循环依赖的场景
(1)构造器的循环依赖。(Spring并未解决这种循环依赖的场景问题) (2)field属性的循环依赖。
Spring中Bean实例化的流程
以AService 依赖 BService, BService 依赖AService 举例说明
1. 将AService的class对象解析成BeanDefinition
1.1将该对象标记为create状态,放入一个Map中
2. 利用反射生成 AService对象;
2.1 此时的对象是一个原始对象
2.2将原始对象放入三级缓存的Map中(稍后会在代码中解释)
2.3 放入三级缓存Map中的key:AService, value:一个lambda表达式
3.填充AService对象的属性(也叫依赖注入)
3.1属性中需要bService,会去单例池里面去找
3.2 单例池里面找不到bService,会去二级缓存Map中去找
3.3 二级缓存中仍然找不到bService,则此时会去创建BService对象。(又开始执行第一步将class解析成BeanDefinition以及第2步......)
3.4填充BService对象的属性------>去单例池中寻找AService没找到------>去二级缓存Map中去找------>三级缓存中找----->找到了lambda表达式(原始对象)----->执行表达式生成AService----->执行aop(此时是提前aop)----->生成aService代理对象----->放入二级缓存map中<aService,代理对象>----->三级缓存map.remove("aService")删除2.3步中放入Aservice相关信息
4. 执行Aware相关代码(如果BService实现了Aware接口,会回调Aware相关方法)
5.初始化BService对象
6.执行BService的AOP
7.将BService放入单例池
8.如果AService实现了Aware接口,则回调AService的方法.----->初始化AService对象----->执行AService的AOP----->将AService放入单例池
三个缓存的作用
一级缓存:就是Spring的单例池Map
二级缓存: 如果Bean对象提前AOP ,二级缓存存放的是对象的代理对象;如果对象没有提前AOP,二级缓存存放的是原始对象
三级缓存:存放Bean的原始对象的Lambda表达式(如果Bean提前AOP需要依赖原始对象,该原始对象是在三级缓存中获取的)
注意:二级缓存存放了Bean的对象之后,三级缓存中需要把存放的lambda表达式删除掉
代码解读下一篇在解读,代码确实有点绕!
欢迎扫码关注
如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!
文章原文地址