什么是循环依赖?

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

Spring中循环依赖场景有:
(1)构造器的循环依赖
(2)field属性的循环依赖。
1. filed 属性注入的循环依赖代码

@Service
public class A {@Autowiredprivate B b;
}@Service
public class B {@Autowiredprivate A a;
}

Spring 解决这个问题是通过 Java 的引用传递,以及提前暴露对象到三级缓存中和延后设置 field 属性来实现的。

如果把 bean 的创建过程简述为 2 个步骤的话:第一步是创建一个对象(通过反射);第二步是给对象填充属性。
Spring 在创建 bean 的时候并不是等它完全完成,而是将创建中的 bean 提前曝光(即加入到 singletonFactories
三级缓存中),当下一个 bean 创建的时候需要依赖此 bean ,则从三级缓存中获取。


Spring 解决field属性注入引发循环依赖的过程:

如果把 bean 的创建过程简述为 2 个步骤的话:第一步是创建一个对象(通过反射);第二步是给对象填充属性
Spring 在创建 bean 的时候并不是等它完全完成,而是将创建中的 bean 提前曝光(即加入到 singletonFactories 三级缓存中),当下一个 bean 创建的时候需要依赖此 bean ,则从三级缓存中获取。

1.先创建A对象,A对象创建完后放到Spring的三级缓存;
2.此时A对象的b属性为空,需要注入b属性,先去三级缓存找B对象,没有找到,此时触发B对象的创建流程。
3.创建B对象,并将创建出来的B对象放进三级缓存中,
4.B对象的b属性为空,需要填充a属性,然后在三级缓存中找到A对象注入属性a,
5.最后再将A对象的b属性进行填充,从缓存中顺利拿到B对象,进行属性注入,循环依赖到此解决。

spring的一二三级缓存:
singletonObjects:
:一级缓存,用于存放完整的bean,从该缓存取到的bean可以直接使用;
earlySingletonObjects::二级缓存,存放提前暴露的bean,bean是不完整的,未完成属性注入和init方法,用于解决循环依赖。
singletonFactories:三级缓存,对初始化后的bean完成AOP代理操作,bean初始化完成之后才生成代理,而不是实例化之后就生成代理,保证了bean的生命周期。

一级缓存和二级缓存比较容易理解,因为只有一级缓存的话,里边既有完整的 bean,也会有尚未初始化的 bean,这样在获取到尚未初始化的 bean 进行调用的时候,就会出现问题。

如果注入的都是普通对象的话,一级缓存和二级缓存已经能解决循环依赖问题。

但是如果是代理对象的话,如果只有一级缓存和二级缓存,那在对象实例化之后就必须要马上创建一个代理对象,这样就违背了 Spring 结合 AOP跟 Bean 的生命周期的设计,Spring 结合 AOP 跟 Bean 的生命周期本身就是通过
AnnotationAwareAspectJAutoProxyCreator 这个后置处理器来完成的,所以 Spring
才会通过三级缓存来保证创建普通对象和创建代理对象时 bean 的生命周期流程统一。

怎么解决构造器注入引发的循环依赖问题?
我们可以通过两种方式来解决构造器注入引发的循环依赖问题:
1.第一种是通过 @Scope 的 proxyMode 属性来设置类的代理模式;
2.第二种是使用 @Lazy 注解。
1.通过 @Scope 的 proxyMode 属性来设置类的代理模式代码示例:

@Service
public class A {private B b;@Autowiredpublic A(B b) {this.b = b;}}@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) // 使用 CGLIB 动态代理
@Service
public class B {private A a;@Autowiredpublic B(A a) {this.a = a;}}

@Scope 注解是 Spring IOC 容器中的一个作用域,默认为 singleton(单例)。通过 Scope 中的 proxyMode 属性可以设置类的代理模式,

DEFAULT 不使用代理
NO 不使用代理
INTERFACES
使用 JDK 动态代理
TARGET_CLASS 使用 CGLIB 动态代理

这里我们不对 @Scope 做过多介绍,上边代码中因为 B 类没有实现接口,不能使用 JDK 动态代理,所以这里使用的是 CGLIB 动态代理。
使用 @Lazy 注解的代码示例:

@Service
public class A {private B b;@Autowiredpublic A(@Lazy B b) {this.b = b;}}@Service
public class B {private A a;@Autowiredpublic B(A a) {this.a = a;}}

@Lazy 注解用于标识 bean 是否需要延迟加载。

当我们通过上述两种方式进行代码改动后,再次启动程序就不会抛出异常了。
那,这两种方式又是如何解决循环依赖问题的呢?

其实它们 都是通过动态代理来避免了循环依赖。
我们再来描述一下 解决循环依赖的过程:
1.创建 A 时需要 B ,发现 B 是可以延迟加载或者是指定了代理模式的;
2.创建一个 B 类的代理类 Bproxy ;
3.通过 Bproxy 创建 A(此时 A 的依赖关系已经变成了 A 依赖 Bproxy);
4.再创建 B 时,A 已经存在,所以 B 也成功创建。

循环依赖视频

循环依赖

Spring循环依赖以及解决方法相关推荐

  1. spring循环依赖及解决方法

    一.三种循环依赖的情况 ①构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常. ②单例模式下的setter循环依赖:通过& ...

  2. Spring 循环依赖 以及解决方式

    目录 什么是循环依赖 如何解决循环依赖 两层可不可以? Spring 是如何解决循环依赖问题的_从菜鸟到放弃的博客-CSDN博客_spring 循环依赖怎么解决 什么是循环依赖 多个bean之间相互依 ...

  3. map 循环_被问到Spring循环依赖怎么解决?秀给面试官看!内附图解

    不知道最近有没有被一道Java面试题刷爆朋友圈,Spring框架的循环依赖如何解决.我收到了不少粉丝的提问,在了解到之后,也去网上查询了一些资料,自己也询问了身边的同事,总结出以下几个方面,今天就和我 ...

  4. spring相互依赖怎么解决_被问到Spring循环依赖怎么解决?秀给面试官看!内附图解...

    不知道最近有没有被一道Java面试题刷爆朋友圈,Spring框架的循环依赖如何解决.我收到了不少粉丝的提问,在了解到之后,也去网上查询了一些资料,自己也询问了身边的同事,总结出以下几个方面,今天就和我 ...

  5. spring循环依赖及解决方式_来探究一下Spring 循环依赖的三种方式

    引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错.下面说一下Spring是如果解决循环依赖的. 第一种: ...

  6. Spring循环依赖及其解决方式

    部分原文链接:java 循环依赖_Java详解之Spring Bean的循环依赖解决方案_以太创服的博客-CSDN博客 1,什么是循环依赖: 在spring中,对象的创建是交给Spring容器去执行的 ...

  7. Spring中-IOC-Bean的初始化-循环依赖的解决

    前言 在实际工作中,经常由于设计不佳或者各种因素,导致类之间相互依赖.这些类可能单独使用时不会出问题,但是在使用Spring进行管理的时候可能就会抛出BeanCurrentlyInCreationEx ...

  8. spring循环依赖解决办法

    Spring循环依赖的解决办法!包含代码讲解!!! 大家面试相信遇到过这么一个问题. 面试官问:你知道spring的循环依赖吗,可以讲一下吗? 我:这个我熟啊,循环依赖就是spring构造一个bean ...

  9. Spring-bean的循环依赖以及解决方式___Spring源码初探--Bean的初始化-循环依赖的解决

    本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可以应用在我们实际开发项目中. 什么是循环依赖? 怎么检测循环依赖 Spring怎么解决循环依赖 S ...

最新文章

  1. IIS 6.0 401 错误
  2. 又拍网架构-又一个用到python的网站
  3. scrapy安装_爬虫框架Scrapy简介与安装
  4. CABAC熵编码代码实现(H264)-FFMPEG
  5. CSU 1805 Three Capitals(矩阵树定理+Best定理)
  6. 苹果mac最好用的视频下载软件:Downie 4
  7. 11. 禁止异常(exceptions)流出destructors之外
  8. Kibana 自定义索引模式 Index patterns
  9. CVE-2017-8046 复现与分析
  10. 不确定单机械臂的自适应反步控制建模与仿真
  11. 在Word文档中快速插入水平线
  12. QT设置选中的文字加下划线
  13. 计算机系调剂到化工专业难不难,华东理工大学大一我被调剂到无机非金属我想转专业..._造价工程师_帮考网...
  14. Xcode13.3 13.2以及Flutter新版本的稳定性问题
  15. 日期转毫秒,毫秒转日期
  16. Excel VBA:设置行高与列宽
  17. 东秦OJ_1841: 超级密码
  18. 学习淘淘商城第十六课(展示后台管理页面)
  19. ClickHouse查询语句详解
  20. kubeadm搭建的K8S集群升级

热门文章

  1. 人死后就不用还信用卡了?别想得太天真!
  2. screen tmux 技巧:linux后台运行程序
  3. Textured Neural Avatars 论文方法简述
  4. 基于Transformer的语音合成
  5. WORD 2010里无法使用输入法解决办法
  6. 操作系统接口之系统调用
  7. 精密仪器的长期稳定性研究
  8. 教女朋友学习 vue中的过滤器及其时间格式化
  9. 关于光猫超级密码和ipv6设置、iptv设置
  10. python连接网络服务器,亲测可用,到此一游