spring循环依赖源码解决分析
2020-01-13 23:21
549 查看
Bean的生命周期以及三级缓存介绍
描述
循环依赖是我们在开发中会经常遇到的一种现象,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
由上图可以了解到,
- 在创建早期对象的时候是根据构造器去创建的,此时没有给早期对象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的情况
构造器注入循环依赖
流程如下图
- 创建早期对象beanA的时候,就需要获取beanB
- 缓存中不存在beanB,开始创建beanB
- 创建beanB的早期对象,此时需要去获取beanA
- beanA在缓存中获取不到,开始获取beanB
- 然后就是2,3,4循环,最后就报错结束
总结
1.spring提供了三级缓存,用来解决非构造器注入循环依赖的问题
2.在写代码的时候不要使用构造器注入的方式注入循环依赖的bean
3.文章短。
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Spring循环依赖的解决办法——带源码分析
- Spring IOC 容器源码分析 - 循环依赖的解决办法
- spring源码分析 循环依赖
- Spring IOC 容器源码分析 - 循环依赖的解决办法
- Spring源码学习--Bean对象循环依赖问题解决(四)
- Spring循环依赖--源码分析
- 从spring源码角度分析循环依赖bean的组装
- Spring源码解析笔记5——循环依赖的解决
- spring 源码探索--单例bean解决循环依赖问题
- Spring源码解析 ---- 循环依赖
- Spring源码解读--(二、Spring如何判断构造器注入时的循环依赖)
- SPRING循环依赖(circular reference)的解决方法 [转贴]
- SPRING循环依赖(circular reference)的解决方法
- 详解Spring-bean的循环依赖以及解决方式
- Spring的三层缓存,解决循环依赖问题
- Spring中的循环依赖问题介绍及解决方法
- Spring中的循环依赖解决详解
- Spring源码(六)-Spring循环依赖的解决方案
- Spring依赖注入源码分析
- 同学,Spring 是怎么解决循环依赖的?