Spring 循环依赖(circular dependency)
一、什么是循环依赖
循环依赖即循环引用,形成闭环。比如,A 依赖 B,B 又依赖 A,形成了循环依赖;或者 A 依赖 B,B 依赖 C,C 又依赖 A,形成了循环依赖;更或者是自己依赖自己。如图:
这不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。Spring 循环依赖场景有:
- 构造器的循环依赖
- 构造器依赖 + field/setter 依赖(A 的构造器依赖 B,B 的 field/setter 依赖 A)
- field 依赖或者 setter 依赖
具体情况如下:
1️⃣A 的构造方法中依赖 B 的实例对象,同时 B 的构造方法中依赖 A 的实例对象。(无法解决)
2️⃣A 的构造方法中依赖 B 的实例对象,同时 B 的某个 field/setter 需要 A 的实例对象,以及反之。(可以解决)
3️⃣A 的某个 field/setter 依赖 B 的实例对象,同时 B 的某个 field/setter 依赖 A 的实例对象,以及反之。(可以解决)
二、Spring 三大循环依赖
1️⃣构造器注入循环依赖【不能解决】
表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException表示循环依赖。
@Service
public class A {public A(B b) {}
}
@Service
public class B {public B(A a) {}
}
Spring 容器会将每一个正在创建的 Bean 标识符放在一个“当前创建 Bean 池”中,Bean 标识符在创建过程中将一直保持在这个池中,因此如果在创建 Bean 过程中发现自己已经在“当前创建 Bean 池”里时将抛出BeanCurrentlyInCreationException表示循环依赖;而对于创建完毕的 Bean 将从“当前创建 Bean 池”中清除掉。执行结果报错信息为:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation:
Is there an unresolvable circular reference?
根本原因:Spring 解决循环依赖依靠的是 Bean 的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。而构造器表示已经完成实例化,所以构造器的循环依赖无法解决。
2️⃣Singleton Pattern field 属性注入循环依赖【可以解决】
@Service
public class A {@Autowiredprivate B b;
}@Service
public class B {@Autowiredprivate A a;
}
3️⃣prototype 模式 field 属性注入循环依赖【不能解决】
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class A {@Autowiredprivate B b;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class B {@Autowiredprivate A a;
}
对于prototype 作用域的 bean,Spring 容器无法完成依赖注入,因为 Spring 容器不缓存 prototype 作用域的 bean,因此无法提前暴露一个创建中的 bean。
scope="prototype"
意思是每次请求都会创建一个实例对象。两者的区别是:有状态的 bean 都使用 Prototype 作用域,无状态的一般都使用 singleton 单例作用域。
因此本例中启动时是不会报错的(因为非单例 Bean 默认不会初始化,而是使用时才会初始化),所以需要手动 getBean() 或者在一个单例 Bean 内 @Autowired 一下它即可:
// 在单例Bean内注入@Autowiredprivate A a;
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
三、怎么检测是否存在循环依赖
检测循环依赖相对比较容易,Bean 在创建的时候可以给该 Bean 打标,如果递归调用回来发现正在创建中的话,说明循环依赖了。
四、Spring 是如果解决循环依赖的
Spring 通过三级缓存加上“提前曝光”机制,配合 Java 的对象引用原理,比较完美地解决了某些情况下的循环依赖问题。
- A 首先完成了初始化的第一步,并且将自己提前曝光到 singletonFactories 中。此时进行初始化的第二步,发现自己依赖对象 B,就尝试去 get(B),发现 B 还没有被 create,所以走 create 流程。
- B 在初始化第一步的时候发现自己依赖了对象 A,于是尝试 get(A),由于 A 通过 ObjectFactory 将自己提前曝光了,所以 B 能够通过 ObjectFactory.getObject 拿到 A 对象。
- B 拿到 A 对象后顺利完成了初始化阶段 1、2、3,完全初始化之后将自己放入到一级缓存 singletonObjects 中。此时返回 A 中,A 拿到 B 的对象顺利完成自己的初始化阶段 2、3,最终 A 也完成了初始化。
Spring 循环依赖(circular dependency)相关推荐
- 【spring容器启动】之bean的实例化和初始化(文末附:spring循环依赖原理)
本次我们通过源码介绍ApplicationContext容器初始化流程,主要介绍容器内bean的实例化和初始化过程.ApplicationContext是Spring推出的先进Ioc容器,它继承了旧版 ...
- Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)
总览 问题 详解 String.intern()的作用 link LeetCode的Two Sum题 link 什么是可重入锁? link 谈谈LockSupport link 谈谈AQS link ...
- Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3
Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3 总览 问题 详解 String.intern()的作用 link LeetCode的Two Sum题 ...
- spring循环依赖
spring循环依赖主要有三种: 单例引用类型循环依赖(属性):允许 构造器的循环依赖:不允许 多例循环依赖:不允许 单例引用类型循环依赖(属性) pa ...
- 烂了大街的 Spring 循环依赖问题,你以为自己就真会了吗
前言 循环依赖问题,算是一道烂大街的面试题了,解毒之前,我们先来回顾两个知识点: 初学 Spring 的时候,我们就知道 IOC,控制反转么,它将原本在程序中手动创建对象的控制权,交由 Spring ...
- 这个Spring循环依赖的坑,90%以上的人都不知道
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Mythsman 原文:https://blog.myths ...
- 这个 Spring 循环依赖的坑,90% 以上的人都不知道
点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:Mythsman blog.mythsman.com/post/5d838c7c2d ...
- Spring循环依赖的三种方式以及解决办法
Spring循环依赖的三种方式以及解决办法 [转]https://www.cnblogs.com/liuqing576598117/p/11227007.html 示例 https://github. ...
- 聊透Spring循环依赖
本文聊一下和依赖注入密切相关,并且在实际开发中很常见,面试也很喜欢问的一个问题:Spring是怎么解决循环依赖的? 之前就被问过Spring是怎么解决循环依赖的问题,当时年少无知,对Spring源码 ...
最新文章
- 公开课:如何成为一名高级系统运维工程师(架构师)?
- python 循环批量生成变量
- Jvm 系列(三):GC 算法 垃圾收集器
- 设计模式复习-原型模式
- 记录一次缓存系统的优化过程
- python常用指令速查
- Mybatis3 (2)xml映射文件
- java迭代器删除两个_两个迭代器的故事
- Wise Package Studio介绍
- How to Configure Eclipse for Python --- 在eclipse中如何配置pydev
- STORM启动与部署TOPOLOGY
- C语言实现FFT算法
- msvcr71.dll缺失导致Oracle无法连接
- 演示u盘启动盘装系统教程
- 【从蛋壳到满天飞】JS 数据结构解析和算法实现-堆和优先队列(二)
- 西游记笔记与想法(2)
- 移动web学习(一) --- 流式布局, 视口viewpoint ,2倍图和3倍图, less
- 北航计算机组成实验课,北航计算机组成实验Project4
- 定时器、看门狗和RTC
- SAP中GR IR PGI的含义
热门文章
- python爬虫(五)爬虫实战
- stratum mining protocol demo
- kindeditor+粘贴word图片
- 服务器芯片市场国产,飞腾发布国产腾云 S2500服务器芯片 2020中国服务器行业市场全景调研...
- 手动清除jwgkvsq.vmx病毒
- 外贸软件如何提升进出口公司业绩 实现降本增效
- 中招报名网站服务器错误,中考报名显示密码错误 中考网上报名说我密码错误怎么办...
- 51单片机控制LCD1602模块
- 计算机域名DNS设置,电脑设置和查看DNS域名服务器的技巧
- 计算机组装硬件要求,组装电脑必懂的硬件知识,全是干货,教你选购硬件不求人...