Spring循环依赖(Spring三级缓存)

一、什么是循环依赖?

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
在这里插入图片描述

二、官方解释

通过构造器注入,无法解决循环依赖问题,采用setter方式是可以的。
在这里插入图片描述

三、循环依赖场景还原

Spring容器默认是使用单例的,单例是支持循环依赖的,不会报错,原型模式是不支持的,会报错。

public class TestA {

    private TestB testB;

    public TestB getTestB() {
        return testB;
    }

    public void setTestB(TestB testB) {
        this.testB = testB;
    }

    public TestA() {
        System.out.println("TestA-->构造函数");
    }
}
public class TestB {
    private TestA testA;

    public TestA getTestA() {
        return testA;
    }

    public void setTestA(TestA testA) {
        this.testA = testA;
    }

    public TestB() {
        System.out.println("TestB-->构造函数");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 
	scope="singleton" 单例模式是正常的,不会报错,已经解决了依赖循环
	scope="prototype" 原型模式是不支持,执行代码时会报错
	-->
    <bean id="testA" class="com.guocoffee.spring.circular.TestA" scope="prototype">
        <property name="testB" ref="testB"></property>
    </bean>
    <bean id="testB" class="com.guocoffee.spring.circular.TestB" scope="prototype">
        <property name="testA" ref="testA"></property>
    </bean>

</beans>
public class test {
    public static void main(String[] args) {
        ApplicationContext aop = new ClassPathXmlApplicationContext("circular.xml");
        TestA testA = aop.getBean(TestA.class);
        TestB testB = aop.getBean(TestB.class);
    }
}
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testA' defined in class path resource [circular.xml]: 
Cannot resolve reference to bean 'testB' while setting bean property 'testB'; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'testB' defined in class path resource [circular.xml]: 
Cannot resolve reference to bean 'testA' while setting bean property 'testA'; 
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
Error creating bean with name 'testA': Requested bean is currently in creation:
 Is there an unresolvable circular reference?

在这里插入图片描述

四、Spring怎么解决循环依赖

源码类名:DefaultSingletonBeanRegist

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;
    // 第一级缓存(singletonObjects):也叫单例池,用于存放完全初始化好的 bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    // 第三级缓存(singletonFactories):单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    // 二级缓存(earlySingletonObjects):提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);

单例的bean是通过三级缓存提前暴露来解决循环依赖的,而非单例的bean(原型),每次从容器中获取到一个新对象,是没有缓存的,是不会存在三级缓存中的。

五、源码解析

实例化:只是申请了一块内存空间(相当于毛坯房)
初始化:完成属性的赋值(装修、家电)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值