spring 是如何解决循环依赖的?

何为循环依赖

  1. 自己依赖自己
  2. 两个对象相互依赖
  3. 多个对象依赖成一圈

循环依赖得场景

在这里插入图片描述

public class A {
	private B b;

	public A(B b) {
		this.b = b;
	}

	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
}
public class B {
	public B(A a) {
		this.a = a;
	}

	public A getA() {
		return a;
	}

	public void setA(A a) {
		this.a = a;
	}

	private A a;

	@Async
	public void test1() {
	}
}
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean name="a" class="com.wfg.spring.xmlstrat.A" >
		<constructor-arg name="b" ref="b"></constructor-arg>
<!--		<property name="b" ref="b"></property>-->
	</bean>
	<bean name="b" class="com.wfg.spring.xmlstrat.B">
<!--		<constructor-arg name="a" ref="a"/>-->
		<property name="a" ref="a"/>
	</bean>
</beans>

单例setter 注入 和 多例setter注入

这个又分一下几个一下几个情况:
AB都是单例情况
AB其中有一个是单例模式
AB全部是多例模式
ps: 单例是在容器初始化时就进行创建好对象放入一级缓存中,多利模式的不进行创建只有使用的时候才进行创建

添加 scope=“prototype” 就是多例;

单例模式:
在这里插入图片描述
AB全是多例模式
在这里插入图片描述

使用源码分析

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
在这里插入图片描述
从这个图片上可以看出spring容器初始化时只加载单例模式的,这个地方说明:AB都是多例情况下不会被加载
但是为啥AB其中有一个为单例的情况下又可以了,如果其中有一个是单例的情况下这个入口就可以进入,
流程就演变成下面的情况了:
在这里插入图片描述

二级缓存的缓存的意义何在?

从上面我们分析来看二级缓存的意义没啥用处,我们这个举例非常简单如果演变成下面的
A
当其中一个类一单从三级缓存中创建对象后即将该对象放入二级缓存中(ps此时该对象还没初始化完成,属于正在创建中),如果后面在有其他对象需要此对象直接从二级缓存中获取(ps如果从三级缓存中获取对象就不是单例了)
在这里插入图片描述
有源码我们可以知道一旦从二级缓存中获取到了也就不用从三级获取了:
ps: 循环依赖主要是靠的二级缓存,三级缓存的主要是解决bean能进行增强得,不是为了解决循环依赖的问题

构造器注入

在这里插入图片描述

从图中的流程看出构造器注入没能添加到三级缓存,也没有使用缓存,所以也无法解决循环依赖问题.和全部是多例情况差不多

单例代理对象setter注入

这种注入方式其实也比较常用,比如平时使用:@Async注解的场景,会通过AOP自动生成代理对象。

@Component
public class A {

	@Autowired
	private B b;
	@Async
	public void test1() {
	}
}

在类A中添加

@Async
	public void test1() {
	}

启动报错:
在这里插入图片描述

说白了,bean初始化完成之后,后面还有一步去检查:第二级缓存 和 原始对象 是否相等。由于它对前面流程来说无关紧要,所以前面的流程图中省略了,但是在这里是关键点,我们重点说说:

在这里插入图片描述
如果增加这一段代码放到B中或者将A的名字修改成C/D再B之后的就可以了
what? 这又是为什么?这就要从spring的bean加载顺序说起了,默认情况下,spring是按照文件完整路径递归查找的,按路径+文件名排序,排在前面的先加载。所以A比B先加载,而改了文件名称之后,B比C先加载。

DependsOn循环依赖

@DependsOn 或者xml中配置dependson属性

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
该方法中:
在这里插入图片描述
此处说明正在创建的类和自己依赖的类存在相互依赖直觉报错.

如何解决循环依赖问题

在这里插入图片描述

源码分析查看

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值