spring循环依赖

Spring中的循环依赖是指在Spring容器中,两个或多个Bean之间相互依赖,形成了一个闭环的依赖关系。以下是关于Spring循环依赖的详细介绍:

循环依赖的类型

  • 构造器循环依赖:Bean A的构造函数中需要注入Bean B,而Bean B的构造函数中又需要注入Bean A,这种情况在Spring中是无法解决的,会导致BeanCurrentlyInCreationException异常。因为构造器注入是在Bean实例化的过程中进行的,在这种循环依赖下,Spring无法完成Bean的实例化。
  • 字段注入循环依赖:Bean A通过字段注入的方式依赖Bean B,而Bean B又通过字段注入依赖Bean A。
  • setter方法循环依赖:Bean A通过setter方法注入Bean B,Bean B又通过setter方法注入Bean A。这种情况与字段注入类似,Spring容器在处理时也会面临挑战。

Spring解决循环依赖的原理

Spring通过三级缓存来解决循环依赖问题,这三级缓存分别是:

  • 一级缓存singletonObjects,用于存储已经创建好的单例Bean对象,是一个ConcurrentHashMap。当Spring创建好一个单例Bean后,会将其放入这个缓存中,以后再获取该Bean时,直接从这里获取。
  • 二级缓存earlySingletonObjects,用于存储早期暴露的Bean对象。在Bean的创建过程中,当Bean完成实例化但还未进行属性填充等后续操作时,会将其提前放入二级缓存。这个缓存主要是为了解决循环依赖时,让其他Bean能够提前获取到正在创建中的Bean的引用。
  • 三级缓存singletonFactories,用于存储Bean工厂对象。在创建Bean时,如果发现该Bean可能存在循环依赖,会将一个能够生成该Bean的工厂对象放入三级缓存。其他Bean在需要依赖该Bean时,可以通过这个工厂对象获取到早期的Bean引用。

在Spring创建Bean的过程中,会按照以下步骤利用三级缓存来处理循环依赖:

  1. 首先从一级缓存singletonObjects中获取Bean,如果能获取到,说明Bean已经创建完成,直接返回。
  2. 如果一级缓存中没有,就从二级缓存earlySingletonObjects中获取。如果能获取到,说明这是一个早期暴露的Bean,也直接返回。
  3. 如果二级缓存中也没有,就从三级缓存singletonFactories中获取对应的Bean工厂。如果有,就通过工厂获取早期的Bean引用,并将其放入二级缓存,同时从三级缓存中移除。
  4. 如果三级缓存中也没有,就开始创建Bean。在创建过程中,如果发现Bean存在依赖其他Bean的情况,就会先去创建依赖的Bean,然后再回来继续完成当前Bean的创建。在创建依赖的Bean时,同样会按照上述步骤检查缓存,处理可能存在的循环依赖。

示例代码

以下是一个简单的Spring循环依赖的示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {
    @Autowired
    private B b;

    public A() {
        System.out.println("A的构造函数");
    }

    public void doSomething() {
        System.out.println("A执行某个操作");
    }
}

@Component
public class B {
    @Autowired
    private A a;

    public B() {
        System.out.println("B的构造函数");
    }

    public void doSomething() {
        System.out.println("B执行某个操作");
    }
}

在上述代码中,A类依赖B类,B类又依赖A类,形成了循环依赖。如果在Spring项目中运行这段代码,Spring容器会通过三级缓存机制来解决这个循环依赖问题,确保AB都能正确创建和注入。

注意事项

  • 多例Bean的循环依赖:Spring默认是不支持多例Bean的循环依赖的,因为多例Bean在每次获取时都会创建一个新的实例,无法像单例Bean那样通过缓存来解决循环依赖。
  • 延迟加载:可以使用@Lazy注解来延迟Bean的加载,对于一些可能存在循环依赖但又不是在启动时就必须使用的Bean,可以通过延迟加载来避免循环依赖问题在启动时就暴露出来。
#面试被问“你的缺点是什么?”怎么答##JAVA面经##面试时最害怕被问到的问题##牛客创作赏金赛#
职保镖-扶你上马 文章被收录于专栏

知识分享,交天下朋友,扶你上马,送你一层,职业规划,面试指导、高薪谈判、背调辅助

全部评论

相关推荐

7.4号一面,面试官就是对着你写的掌握的技术栈问八股,背的还行,面试官说过了。# 七牛云一面- 1.介绍下 SSO 是什么?- 2.介绍下 RBAC 是什么?了解过其他的鉴权模型吗?用户判断是否能执行某个接口的具体流程?- 3.了解 Go 语言的相关知识吗?- 4.Mysql语句调优具体怎么做?(说到覆盖索引减少回表的时候问了回表具体是什么)- 5.explain命令有哪些字段?- 6.Mysql事务的特性?- 7.Mysql的几种隔离级别?各解决了什么问题?默认是什么隔离级别?- 8.MVCC的具体实现?- 9.除了事务还有哪些方式可以解决幻读?- 10.next-key lock是什么级别的锁?什么情况下会退化成记录锁或间隙锁?- 11.建议一张表要完整考虑什么?(给了提示:表名,字段名,数据类型选择,存储引擎,索引,编码格式等)- 12.表名或者字段名可以用 order 吗?- 13.存储引擎有哪些?InnoDB和MyISAM执行查询语句花费时间一样吗?- 14.Redis怎么保证缓存一致性?延迟双删什么情况还是会出现缓存不一致?- 15.Delete 命令具体流程?- 16.ES的倒排索引?- 17.ES一般是多节点的,怎么实现多节点数据排序?- 18.如果有深度分页,ES会出现什么问题?7.8号二面,面试官就是一行一行挖你的项目了,我是回答的七七八八,不算特别好,我看牛课上其他人二面面完如果过了都是当天立马约hr面的,我这两天没回应了,我估计是挂了## 七牛云二面- 基本就是问项目了,一行一行问你简历上写的东西,下面是几个印象比较深的问题- 1.你的项目你具体负责哪些模块?- 2.如果让你自己实现一个消息队列的功能你会怎么做?(我理解的应该是不用MQ然后实现MQ的功能)- 3.OpenTelemetry实现的链路追踪,你有哪里用到Span标签了吗?- 4.能说下熔断具体是怎么实现的吗?- 5.能说下负载均衡你具体用了什么算法吗?具体怎么实现?- 6.每个结点的抗压能力不一样,如果让你自己来,怎么实现负载均衡呢?- 7.ES的搜索功能你是怎么实现的?字典树是什么?- 8.Agent项目具体是如何实现上下文维护的?- 9.能具体说下LangChain吗?- 10.go的携程和操作系统的线程有什么关系?线程在进行切换的时候会保留什么资源?- 11.java中的哈希表是怎么解决哈希冲突的?- 12.算法题:实现一个线程安全的LRU(LRU会,但线程安全有点不懂,就把 map 换成了 concurrenthashmap )
七牛云二面7人在聊
点赞 评论 收藏
分享
06-23 15:01
已编辑
武汉理工大学 C++
二月底还没好好准备八股和算法,看到身边人开始投简历找暑期实习,我也学着投。3月初在牛客认识该部门接头人,并连续几日打电话跟我说部门很缺人,尤其是ai工程师这个岗位,让官网投他们部门并将简历编号发给他们,于是投递该部门ai工程师并发送简历编号。字节二面挂,腾讯一面挂,快手游戏一面挂。滴滴二面挂,阿里瓴羊一面挂。美的面试通过并offer,但是安排base与我选择的base相距甚远,选择佛山安排到上海,拒绝了offer。此时通过了华为机试,且约到面试,以为会迎来转机,想不到是深渊的开始。timeline:4月16日笔试,345分通过4月17日性格测评4月29下午一面+主管面通过并满足11.45+25小时入池,当天接到网易雷火电话,同天29号晚上完成雷火一面。5月7日,雷火主管面(好像是因为觉得我不够对口,给我转为日常实习所以技术面只有一面),5月8日雷火HR面通过并OC,并询问是否有其他选择。5月9日,雷火HR打电话催促决定。5月11日,选择相信华为,并拒绝雷火日常实习offer。5月19日接到华为接头人保温电话,询问意向和薪资相关,并说过几天会有邮件offer。5月29日,由于鼠鼠在牛客已经看到有人泡出来了,实在倍感焦虑于是询问接头人,这周能否收到offer,已读不回。6月3日再次询问接头人,接头人回答已经帮我询问上面,但是上面不答复她。6月7日,再次询问接头人是否有回复,接头让回答可能开不出来了。6月18日,和我同样投递该部门,投递岗位为数字ICT工程师的同学,同期一面,但是6月6日才完成主管面,收到邮件offer。遂再度联系接头人,接头人告知争取不到了,实在没办法 抱歉。化身华黑。以下为一些聊天记录,能避雷该部门就避雷。总结一下:没拿到邮件offer前,HR的话一句都不能信。
我亚索又来了:华为老传统了,看到好多都这样的,没拿到offer之前不要相信hr的任何话
华为求职进展汇总
点赞 评论 收藏
分享
06-22 13:06
吉林大学 Java
从 4.26 号开始投递简历,各个大厂都投了一遍,以为会遇到各种面试时间冲突的情况,结果却在无限的泡池子中…5.10、5.11 做了美团和 pdd 的笔试,最先收到了 pdd 的约面,一面感觉答的不咋好,结果进了二面,二面感觉答的还行,结果隔一天后挂了,真就不能有侥幸心理,感觉挂了那就是挂了。后来美团和飞猪相继约面,飞猪问了几个问题,聊了不到 15min 就甩三道题自个做去吧,过几天挂了。美团一面秒过,二面遇到一个很严肃的面试官,问的是非常规的问题,而且揪着不放,也挂了。美团捞了一次,成都闪购,牛客上都听说成都没 hc 了,还捞我干啥?一面面的很好,隔了四天挂了,感觉压根不缺人。然后是京东,调剂的数开岗位捞了,一面不咋地,手撕也没撕出来,然后进二面了?二面遇到个贼离谱的面试官,有点 pua 式的问题,就是无伤大雅的一些点拿出来说事,让你觉得是你自己准备的不好导致的,但回想起来,那些个问题根本毫无技术含量可言,单纯就是为了刷人吧。后续京东零售后端捞了,一面的邮件写了 30min,但却面了 1h,对着我简历随机提问,单纯的八股,也都一一答出来了,面试官说我基础很扎实,肯定给我过,后边就看他的上级怎么安排了。我大概听出来了他的意思,基础不错,但是没实习,不一定能有后续。果然,二面应该是个 leader,从感觉上就能知道这不是一个普通的开发,简单的自我介绍了一下,听完之后空窗了几秒钟,感觉对我没有兴趣,就问了项目有什么亮点,谈谈 spring ai,我回答的时候他是闭眼扶头的姿势,感受到他的疲惫和无感,反问期间给的回答的大体意思是想招有经验的实习生,可能也是出于对我的同情?他说尽量给我面评写的好一点,不管过或者不过,二十分钟结束…第二天约三面了,我结合以往的面试经历,觉得不能存在侥幸心理,还是得踏踏实实的走后每一步,京东肯定是过不了的,即使是到了三面,我就自觉的拒面了,也是给自己留下最后一丝体面吧其他的大厂基本就是简历挂了或者不推进不过值得高兴的是,我在 ssob 上投了其他中小厂,用友金融给我了第一个 offer,一面十五分钟,二面十七分钟,两个工作日收到 offer,于是兴冲冲的来了北京,720 一个月的宿舍有被震撼到,哈哈哈对接我的 hr 人超级好,是个暖心的大姐姐,我有些入职小白的问题不懂的问她都有回复,而且宿舍问题也帮我安排,真的超级赞,感觉在这里遇到的每一个人都很好!刚入职两天,还没有什么活儿,配了环境,拉了代码,应该不是客开和低代码,主要的工作可能还是改 bug?感谢用友收留了我,也很感恩在这里遇到的小伙伴们。暑期应该是收尾了,面试已经麻木了,已经接不到面试了,也不想再面了,开始沉淀自己了,备战秋招!祝各位牛油也能拿到自己心仪的 offer!
一片特立独行的面包:你想多了,狗东不难,而且今年大量招实习生,三面就是HR面
点赞 评论 收藏
分享
评论
3
15
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务