文章目录

  • 什么是循环依赖?
  • 循环依赖的产生
    • 1 构造器方式产生的循环依赖(spring本身无法解决,抛出异常)
    • 2 setter方法产生的循环依赖
    • 3 setter方式原型,prototype
  • spring用三级缓存解决循环依赖问题:
  • 总结

什么是循环依赖?

循环依赖就是循环引用 ,指两个或者多个bean互相持有依赖对方,比如A引用B, B引用C,C引用A,最终形成一个闭环

补充: 注意区别于循环调用;

什么是循环调用?
指方法之间的环调用,循环调用是无解的,除非有终结条件,否则就是死循环,最终会导致内存溢出异常

循环依赖的产生

1 构造器方式产生的循环依赖(spring本身无法解决,抛出异常)

表示通过构造器注入造成的循环依赖,此依赖是无解的,强行依赖只能抛出异常BeanCreationException;

bean的创建过程:
spring容器将每一个正在创建的bean标识符放在一个当前创建的bean池中,bean标识符在创建过程中将一直保持在这个池中,因此在创建bean的过程中如果发现自己已经在池中,则抛出BeanCreationException异常表示循环依赖,而对于创建完成的bean将从 当前创建bean池中清除掉;

出现依赖错误的原因:
Spring容器先创建单例A,A依赖B,然后将A放在“当前创建Bean池”中,此时创建B, B依赖C,然后将B放在“当前创建Bean池”中,此时创建C,C又依赖A, 但是,此时A已经在池中,所以会报错,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,(初始化完的Bean会从池中移除)

2 setter方法产生的循环依赖

指通过setter注入方式构成的循环依赖。

spring实例化bean流程图:

spring的解决办法:
Spring先用构造器实例化Bean对象----->将实例化结束的对象放到一个Map中,并且Spring提供获取这个未设置属性的实例化对象的引用方法。结合我们的实例来看,,当Spring实例化了StudentA、StudentB、StudentC后,紧接着会去设置对象的属性,此时StudentA依赖StudentB,就会去Map中取出存在里面的单例StudentB对象,以此类推,就不会出来循环的问题。

3 setter方式原型,prototype

错误原因:
scope=“prototype” 意思是 每次请求都会创建一个实例对象。

两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring

容器不进行缓存,因此无法提前暴露一个创建中的Bean。

spring用三级缓存解决循环依赖问题:

三级缓存如下:

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

名词解释:
singletonObjects :指单例对象的cache
singletonFactories: 指单例对象工厂的cache
earlySingletonObjects:指提前曝光的单例对象的cache

举例解释三级缓存的实际应用:

如A依赖B,B依赖C的场景:

A完成初始化第一步,并且将自己提前曝光到singletonFactories中,
此时进行初始化的第二步,发现自己依赖对象B,就去get(B),发现B还没有被初始化,所以走初始化流
程,
B在初始化第一步发现自己依赖于A,于是尝试get(A),
尝试一级缓存singletonObjects(A还没有完全初始化),
尝试二级缓存earlySingletonObjects(也没有),
尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能通过ObjectFactory.getObject拿到A对象(尚未完全初始化的状态),
B拿到A对象后顺利完成了初始化阶段1,2,3,完全初始化之后将自己放入到一级缓存singleObjects中,
此时返回A,A此时能拿到B的对象顺利完成自己的初始化阶段2,3,最终A也完成了自己的初始化阶段,放入到一级缓存singletonObjects中;

总结

Spring通过三级缓存加上“提前曝光”机制,配合Java的对象引用原理,比较完美地解决了某些情况下的循环依赖问题!

参考1
参考2

面试题:spring的循环依赖问题以及如何解决相关推荐

  1. Spring中循环依赖问题

    1.什么是Spring中的循环依赖 循环依赖就是循环引用,也就是两个或者两个以上的Bean相互持有对方,最终形成闭环.比如A依赖于B,B依赖于C,C又依赖于A. 2.Spring处理循环依赖的机制 无 ...

  2. Spring当中循环依赖很少有人讲,今天一起来学习!

    网上关于Spring循环依赖的博客太多了,有很多都分析的很深入,写的很用心,甚至还画了时序图.流程图帮助读者理解,我看了后,感觉自己是懂了,但是闭上眼睛,总觉得还没有完全理解,总觉得还有一两个坎过不去 ...

  3. 被问麻了,Spring 如何处理循环依赖?

    点击关注公众号,利用碎片时间学习 前言 Spring如何处理循环依赖?这是最近较为频繁被问到的一个面试题,在前面Bean实例化流程中,对属性注入一文多多少少对循环依赖有过介绍,这篇文章详细讲一下Spr ...

  4. Spring源码剖析-Spring如何处理循环依赖

    前言 你是不是被这个骚气的标题吸引进来的,_ 喜欢我的文章的话就给个好评吧,你的肯定是我坚持写作最大的动力,来吧兄弟们,给我一点动力 Spring如何处理循环依赖?这是最近较为频繁被问到的一个面试题, ...

  5. spring 循环依赖_简单说说 Spring 的循环依赖

    作者 | 田伟然 回首向来萧瑟处,归去,也无风雨也无晴. 杏仁工程师,关注编码和诗词. 前言 本文最耗时间的点就在于想一个好的标题, 既要灿烂夺目,又要光华内敛,事实证明这比砍需求还要难! 由于对象之 ...

  6. Spring中循环依赖的解决办法

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 1.什么是循环依赖? 循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方. A类中有一个B类型的成员变量, ...

  7. Spring当中循环依赖很少有人讲,今天让我们来看看吧

    网上关于Spring循环依赖的博客太多了,有很多都分析的很深入,写的很用心,甚至还画了时序图.流程图帮助读者理解,我看了后,感觉自己是懂了,但是闭上眼睛,总觉得还没有完全理解,总觉得还有一两个坎过不去 ...

  8. Spring IOC循环依赖问题

    Spring IOC循环依赖问题 什么是循环依赖 循环依赖其实就是循环引用, 也就是两个或者两个以上的Bean互相持有对方,形成闭环,例如:A依赖B,B依赖C,C又依赖于A. Spring中循环依赖的 ...

  9. Spring IOC循环依赖

    Spring IOC循环依赖 什么是循环依赖 Spring中Bean实例的创建流程 Spring三级缓存 ClassA创建流程 思考 什么是循环依赖 ClassA中依赖ClassB ClassB中依赖 ...

  10. 【源码分析】Spring的循环依赖(setter注入、构造器注入、多例、AOP)

    写在前面 首先最简单的循环依赖demo就是:A->B 且 B->A.本文围绕这个例子去讲解setter注入的循环依赖.构造器注入循环依赖.多例的循环依赖.带AOP的循环依赖.以下是一些结论 ...

最新文章

  1. ISIS和OSPF的比较
  2. Linux运维工程师必备技能
  3. JVM:内存划分总结
  4. 2017年11月01日普及组 I Got a Matrix!
  5. C语言实现hash/DJB2算法(附完整源码)
  6. 这本关于Node.js的书,是一本神书,助你学会Node.js,为你升职加薪,走上人生巅峰
  7. 【CodeVS】1993草地排水
  8. mysql同步多主,MySQL多主一从同步配置
  9. 淘宝商品比价定向爬虫
  10. 高质量C编程00-汇总
  11. python画spc控制图_如何选择最适合我们的SPC控制图?
  12. centos7 python3 爬虫登陆邮箱_使用爬虫爬取超星学习通的作业时间并且通过邮件提醒!...
  13. mysql返回上一层_mysql常用命令大全
  14. AI--调用百度OCR文字识别API进行图片文字识别
  15. python中3个单引号,Pyhton3中单引号、双引号、三个引号的用法和区别
  16. JZOJ100047. 【NOIP2017提高A组模拟7.14】基因变异
  17. 【NLP】Python NLTK获取文本语料和词汇资源
  18. MATLAB错误使用 surf (第 71 行) X、Y、Z 和 C 不能是复数。解决办法。
  19. 2022年R1快开门式压力容器操作题库及模拟考试
  20. 微信支付成功后不回调的奇葩网络原因

热门文章

  1. 在java中gc是啥_java中,什么是GC?GC的基本原理。
  2. C++ 单例模式-打印机案例
  3. 算法程序-通过log重现计算过程
  4. 解决python使用gmail smtp服务发邮件报错smtplib.smtpauthentic
  5. “花瓣网”首页静态页面(仅供参考)
  6. 重庆大学计算机学院专硕分析,重庆大学电子信息(专硕)专业考研难度分析-专业排名-难度大小...
  7. 对立与统一(期货反向跟单-交易员培训法则)
  8. Squid安装及运行控制_wuli大世界_新浪博客
  9. Windows 10, version 22H2 (released Oct 2022) 简体中文版、英文版下载
  10. html5 手机uc浏览器 复制链接,清除UC手机浏览器强制在页面中加入的关键词链接...