• Spring循环依赖


    一、循环依赖全景图

    在这里插入图片描述

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

    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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    (2)配置文件:

    
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (3)测试代码:

    	@Test
    	public 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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    3、通过Spring IOC流程的源码分析循环依赖问题:

    在这里插入图片描述

    三、循环依赖问题的类型

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

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

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

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

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

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

    在这里插入图片描述

    五、Spring三大缓存介绍

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

    在这里插入图片描述

    1、一级缓存:Map singletonObjects

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

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

    (2)存储什么数据?

    • K:bean的名称
    • V:bean的实例对象(有代理对象则指的是代理对象,已经创建完毕)
    2、第二级缓存:Map earlySingletonObjects

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

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

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

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

    (2)存储什么数据?

    • K:bean的名称
    • V:ObjectFactory,该对象持有提前暴露的bean的引用
      在这里插入图片描述
  • 相关阅读:
    打破对ChatGPT的依赖以及如何应对ChatGPT的错误和幻觉
    微信小程序603300报错,保存文件出错download save file error的解决办法
    [Pandas技巧] 多行合并成一行
    Android 缩短开机动画的播放时长
    Windows开启路由转发功能
    linux系统Jenkins工具的node节点配置
    设计模式:外观模式
    three.js实现3D图形渲染
    【图像融合】基于RP、CVT、DTCWT、NSCT-SR+DWT-SR+拉普拉斯金字塔算法-SR等实现MRT图像融合附matlab源码
    Android shortcuts快捷方式
  • 原文地址:https://blog.csdn.net/qq_37933128/article/details/127199321