spring循环依赖源码解决分析

描述

循环依赖是我们在开发中会经常遇到的一种现象,beanA依赖于beanB,beanB又依赖于beanA,形成了一个循环
在这里插入图片描述
像这样的问题spring提供了三级缓存解决非构造注入的解决方式,但是对于构造器注入的方式,还是会存在问题,原理如下。

代码样例

1.代码结构图
在这里插入图片描述
2.InstantA.java

import org.springframework.stereotype.Component;

@Component
public class InstantA {
	private InstantB ib;

	public InstantB getIb() {
		return ib;
	}

	public void setIb(InstantB ib) {
		this.ib = ib;
	}
}

3.InstantB.java

import org.springframework.stereotype.Component;

@Component
public class InstantB {
	private InstantA ia;

	public InstantA getIa() {
		return ia;
	}

	public void setIa(InstantA ia) {
		this.ia = ia;
	}
}

4.spring.xml

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--  非构造器注入 -->
	<bean id="ia" class="com.zk.test.InstantA">
		<property name="ib" ref="ib"></property>
	</bean>
	<bean id="ib" class="com.zk.test.InstantB">
		<property name="ia" ref="ia"></property>
	</bean>
	<!--  构造器注入 -->
	<!-- <bean id="ia" class="com.zk.test.InstantA">
		<constructor-arg name="ib" ref="ib"></constructor-arg>
	</bean>
	<bean id="ib" class="com.zk.test.InstantB">
		<constructor-arg name="ia" ref="ia"></constructor-arg>
	</bean> -->
</beans>

5.MainConfigure.java

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource(locations="classpath:spring.xml")
@ComponentScan(basePackages= {"com.zk.test"})
public class MainConfigure {

}

6.Main.java

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//上下文 创建IOC容器
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(MainConfigure.class);
		//获取bean  去容器的缓存中直接拿
		InstantA InstantA=(InstantA) ctx.getBean("ia");
		ctx.close();
	}

}

提供测试代码是方便自己debug查看。

非构造器注入循环依赖

在理解这一块之前需要先去看一下我之前写的bean的生命周期和三级缓存,看完这个会对下面bean创建的流程就有了解了。下面是beanA创建的时候如何去获取beanB
在这里插入图片描述
由上图可以了解到,

  1. 在创建早期对象的时候是根据构造器去创建的,此时没有给早期对象beanA赋属性值
    2. 然后spring就把早期对象beanA放入了三级缓存之中,
    3. 继续往下走,就会给早期对象beanA赋属性值,此时就会去获取beanB,而beanB还没有被创建
    4. 调用getBean方法获取benaB,如果beanB不存在就会调用创建方法
    5. 去缓存中获取beanB,不存在调用创建方法
    6. 同理创建beanB的早期对象
    7. 然后spring就把早期对象beanB放入了三级缓存之中,
    8. 给早期对象beanB赋属性值,而此时就会去获取beanA
    9. 调用getBean获取beanA
    10. 可以在缓存中找到beanA,此时返回给beanB,beanB继续创建
    11. beanB创建结束返回给beanA
    12. beanA继续创建
    13. beanA创建结束

以上就是创建的所有,从上述可以看到,需要先创建早期对象,并且放入三级缓存,在填充属性值的时候创建beanB,而如果是构造器方法注入的话,就需要在创建早期对象的时候就开始创建benaB,就会存在缓存中没有存入beanA的情况

构造器注入循环依赖

流程如下图
在这里插入图片描述

  1. 创建早期对象beanA的时候,就需要获取beanB
  2. 缓存中不存在beanB,开始创建beanB
  3. 创建beanB的早期对象,此时需要去获取beanA
  4. beanA在缓存中获取不到,开始获取beanB
  5. 然后就是2,3,4循环,最后就报错结束

总结

1.spring提供了三级缓存,用来解决非构造器注入循环依赖的问题
2.在写代码的时候不要使用构造器注入的方式注入循环依赖的bean
3.文章短。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值