一、循环依赖问题全景图

二、什么是循环依赖问题?

1、什么是循环依赖:

类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。

比如下图中A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题。

2、循环依赖问题案例分析:

(1)演示代码:

public class ClassA {private ClassB classB;public ClassB getClassB() {return classB;}public void setClassB(ClassB classB) {this.classB = classB;}
}
public class ClassB {private ClassA classA;public ClassA getClassA() {return classA;}public void setClassA(ClassA classA) {this.classA = classA;}
}

(2)配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="classA" class="ioc.cd.ClassA"><property name="classB" ref="classB"></property></bean><bean id="classB" class="ioc.cd.ClassB"><property name="classA" ref="classA"></property></bean>
</beans>

(3)测试代码:

 @Testpublic void test() throws Exception {// 创建IoC容器,并进行初始化String resource = "spring/spring-ioc-circular-dependency.xml";ApplicationContext context = new ClassPathXmlApplicationContext(resource);// 获取ClassA的实例(此时会发生循环依赖)ClassA classA = (ClassA) context.getBean(ClassA.class);}

3、通过Spring IOC流程的源码分析循环依赖问题:

三、循环依赖问题的类型

循环依赖问题在Spring中主要有三种情况:

  • (1)通过构造方法进行依赖注入时产生的循环依赖问题。
  • (2)通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
  • (3)通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。

在Spring中,只有第(3)种方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。其实也很好解释:

  • 第(1)种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
  • 第(2)种setter方法(多例)的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。

四、如何解决循环依赖问题?

1、Spring解决的单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过两个缓存来解决的,请看下图:

五、Spring三大缓存介绍

Spring中有三个缓存,用于存储单例的Bean实例,这三个缓存是彼此互斥的,不会针对同一个Bean的实例同时存储。如果调用getBean,则需要从三个缓存中依次获取指定的Bean实例。 读取顺序依次是一级缓存 ==> 二级缓存 ==> 三级缓存。

1、一级缓存:Map<String, Object> singletonObjects:

(1)第一级缓存的作用:

  • 用于存储单例模式下创建的Bean实例(已经创建完毕)。
  • 该缓存是对外使用的,指的就是使用Spring框架的程序员。

(2)存储什么数据?

  • K:bean的名称
  • V:bean的实例对象(有代理对象则指的是代理对象,已经创建完毕)

2、第二级缓存:Map<String, Object> earlySingletonObjects:

(1)第二级缓存的作用:

  • 用于存储单例模式下创建的Bean实例(该Bean被提前暴露的引用,该Bean还在创建中)。
  • 该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。
  • 为了解决第一个classA引用最终如何替换为代理对象的问题(如果有代理对象)

3、第三级缓存:Map<String, ObjectFactory<?>> singletonFactories:

(1)第三级缓存的作用:

  • 通过ObjectFactory对象来存储单例模式下提前暴露的Bean实例的引用(正在创建中)。
  • 该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。
  • 此缓存是解决循环依赖最大的功臣

(2)存储什么数据?

  • K:bean的名称
  • V:ObjectFactory,该对象持有提前暴露的bean的引用

(3)为什么第三级缓存要使用ObjectFactory?

如果仅仅是解决循环依赖问题,使用二级缓存就可以了,但是如果对象实现了AOP,那么注入到其他bean的时候,并不是最终的代理对象,而是原始的。这时就需要通过三级缓存的ObjectFactory才能提前产生最终的需要代理的对象。

(4)什么时候将Bean的引用提前暴露给第三级缓存的ObjectFactory持有?时机就是在第一步实例化之后,第二步依赖注入之前,完成此操作。

六、解决构造函数相互注入造成的循环依赖:

前面说Spring可以自动解决单例模式下通过setter()方法进行依赖注入产生的循环依赖问题。而对于通过构造方法进行依赖注入时产生的循环依赖问题没办法自动解决,那针对这种情况,我们可以使用@Lazy注解来解决。

也就是说,对于类A和类B都是通过构造器注入的情况,可以在A或者B的构造函数的形参上加个@Lazy注解实现延迟加载。@Lazy实现原理是,当实例化对象时,如果发现参数或者属性有@Lazy注解修饰,那么就不直接创建所依赖的对象了,而是使用动态代理创建一个代理类。

比如,类A的创建:A a=new A(B),需要依赖对象B,发现构造函数的形参上有@Lazy注解,那么就不直接创建B了,而是使用动态代理创建了一个代理类B1,此时A跟B就不是相互依赖了,变成了A依赖一个代理类B1,B依赖A。但因为在注入依赖时,类A并没有完全的初始化完,实际上注入的是一个代理对象,只有当他首次被使用的时候才会被完全的初始化。

Spring如何解决循环依赖问题相关推荐

  1. 高频面试题:Spring 如何解决循环依赖?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 在关于Spring的面试中,我们经常会被问到一个问题:Spring ...

  2. 面试问你Spring如何解决循环依赖的时候,不要一脸懵逼了!

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 来源:http://h5ip.cn/AXHC 在关于Spring的面试中,我们经常会被问到一个 ...

  3. Spring 如何解决循环依赖?

    在关于Spring的面试中,我们经常会被问到一个问题:Spring是如何解决循环依赖的问题的. 本文主要针对这个问题,从源码的角度对其实现原理进行讲解. 1. 过程演示 关于Spring bean的创 ...

  4. 人人都能看懂的Spring源码解析,Spring如何解决循环依赖

    人人都能看懂的Spring源码解析,Spring如何解决循环依赖 原理解析 什么是循环依赖 循环依赖会有什么问题? 如何解决循环依赖 问题的根本原因 如何解决 为什么需要三级缓存? Spring的三级 ...

  5. Spring 如何解决循环依赖问题

    在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的. 这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能 ...

  6. 闷棍暴打面试官 Spring源码系列: (一) Spring 如何解决循环依赖

    前言 初夏时节, 时间: AM 7.30分左右, 空无一人的健身房里,一个硕大的身体在跑步机上扭动着, 不一会头上便挥汗如雨, 他嘴上还不时嘀咕着 "循环依赖,单例模式,Bean的定位加载注 ...

  7. Spring系列五:Spring怎么解决循环依赖

    15.说说循环依赖? 什么是循环依赖? Spring循环依赖 Spring 循环依赖:简单说就是自己依赖自己,或者和别的Bean相互依赖. 鸡和蛋 只有单例的Bean才存在循环依赖的情况,原型(Pro ...

  8. spring如何解决循环依赖

    spring中循环依赖有三种情况: 1.构造器注入形成的循环依赖.这种难以解决 2.setter注入构成的循环依赖,可以解决 3.prototype作用域的循环依赖.这种循环依赖同样无法解决. 解决循 ...

  9. 女朋友都能看懂,Spring如何解决循环依赖?

    介绍 先说一下什么是循环依赖,Spring在初始化A的时候需要注入B,而初始化B的时候需要注入A,在Spring启动后这2个Bean都要被初始化完成 Spring的循环依赖有两种场景 构造器的循环依赖 ...

最新文章

  1. 数字信号处理中卷积的图形化动态解释
  2. 马明哲新年内部讲话透露新战略:全面开启3.0时代
  3. 4.2.2 磁盘调度算法
  4. 开源的库RestSharp轻松消费Restful Service
  5. 加密和解密算法的兩個實現
  6. 【编程导航】国外大神总结的实用代码,30 秒学会!
  7. KD-VLP:知识蒸馏和预训练还能这么结合?上科大IntelMSRA提出基于知识蒸馏的端到端多模态预训练模型...
  8. spring-bean(xml方式管理)
  9. 高性能计算GPU解决方案系列课程一--高性能计算简介
  10. 数组模拟栈解决括号匹配
  11. excel宏教程_Excel多功能工具箱(收藏家必备)
  12. Rational Rose打开mdl文件显示“there are warning,see the log for details”问题解决方法
  13. 从这三个维度说一说,如何做一名具有产品思维的UI设计师?
  14. 小程序开发 tips——2
  15. JZOJ_2499_东风谷早苗 (Standard IO)
  16. 频率响应——频率响应基本概念;单时间常数RC电路频率响应
  17. audiosever耗电_audio服务自动停止 - 卡饭网
  18. NoSql入门和概述
  19. android 横幅弹出权限,有关 android studio notification 横幅弹出的功能没有反应
  20. 云服务器如果要挂QQ机器人的话,怎么操作?

热门文章

  1. 二十五、爬取毛豆新车的数据
  2. 期末考试前的预习,科目:化工设备与反应器(1)
  3. 微信小程序开发 使用高德地图(精准一些)
  4. 清华大学高阳:Mastering Atari Games with Limited Data
  5. 一文详解Google最新NLP模型XLNet
  6. 二分图最大权匹配 KM算法
  7. hdu 1874 Dijkstra算法模板
  8. feign直接走熔断_四、Spring Cloud之熔断处理 Hystrix
  9. c语言入门后怎么玩,玩编程如何让人傻并快乐着?
  10. python中统计单词出现的次数_python统计文章中单词出现次数实例