文档章节

Spring bean循环依赖问题,与解决方案。

边鹏_尛爺鑫
 边鹏_尛爺鑫
发布于 2018/11/27 11:59
字数 967
阅读 47
收藏 2

前言

        我们知道 Spring 可以是懒加载的,就是当真正使用到 Bean 的时候才实例化 Bean。当然也不全是这样,例如配置 Bean 的 lazy-init 属性,可以控制 Spring 的加载时机。现在机器的性能、内存等都比较高,基本上也不使用懒加载,在容器启动时候来加载bean,启动时间稍微长一点儿,这样在实际获取 bean 供业务使用时,就可以减轻不少负担,这个后面再做分析。 我们使用到 Bean 的时候,最直接的方式就是从 Factroy 中获取,这个就是加载 Bean 实例的源头。

        最近发现一个问题,一些大的公司(国内知名的boss级别公司就那么几家),在面试的过程中,会问到一个基础题:spring怎么实现循环依赖,或者循环依赖的解决方案。今天主要就这个问题做下简单的探讨:

        3个简单的bean:TestA,TestB,TestC其中A包含B,B含C,C含A。然后把三类注入到spring容器中。操作如下:

A类:

public class TestA {
	
	private TestB testB;

	public TestB getTestB() {
		return testB;
	}

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

B类:

public class TestB {
	
	private TestC testC;

	public TestC getTestC() {
		return testC;
	}

	public void setTestC(TestC testC) {
		this.testC = testC;
	}
}

C类:

public class TestC {
	
	private TestA testA;

	public TestA getTestA() {
		return testA;
	}

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

简单的注入到spring中xml如:

<!-- 循环依赖测试 -->
<bean id="testA" class="com.xin.learn.xhyl.vo.TestA" scope="prototype">
	<property name="testB" ref="testB"></property>
</bean>
<bean id="testB" class="com.xin.learn.xhyl.vo.TestB" scope="prototype">
	<property name="testC" ref="testC"></property>
</bean>
<bean id="testC" class="com.xin.learn.xhyl.vo.TestC" scope="prototype">
	<property name="testA" ref="testA"></property>
</bean>

测试类:

public class TestMain {
	 public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
		System.out.println(context.getBean("testA", TestA.class));
	 }
}

如果你是web项目,运行项目不会报错,但是当你引用的时候,或者运行测试类后发现报错:

Error creating bean with name 'testA' defined in class path resource [spring/applicationContext.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 [spring/applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.xin.learn.xhyl.vo.TestB' to required type 'com.xin.learn.xhyl.vo.TestC' for property 'testC'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.xin.learn.xhyl.vo.TestB] to required type [com.xin.learn.xhyl.vo.TestC] for property 'testC': no matching editors or conversion strategy found

大致意思是:在创建testA的时,设置属性testB的时候不能引用testB。
因为这个时候的testB还没有被创建。

解决:当把 scope的值改为singleton时,或者去掉scope(因spring默认的bean就是单例的),运行就正常了。原因:
        Spring提供了EarlyBeanReference功能,首先Spring里面有个名字为singletonObjects的并发map用来存放所有实例化并且初始化好的bean,singletonFactories则用来存放需要解决循环依赖的bean信息(beanName,和一个回调工厂)。当实例化beanA时候会触发getBean(“beanA”);首先看singletonObjects中是否有beanA有则返回,一开始肯定没有所以会实例化beanA,如果设置了allowCircularReferences=true(默认为true)并且当前bean为单件并且该bean目前在创建中,则初始化属性前把该bean信息放入singletonFactories单件map里面。然后对该实例进行属性注入beanB,属性注入时候会getBean(“beanB”) ,发现beanB 不在singletonObjects中,就会实例化beanB,然后放入singletonFactories,然后进行属性注入beanA,然后触发getBean(“beanA”);这时候会到(1)getSingleton返回实例化的beanA。到此beanB初始化完毕添加beanB 到singletonObjects然后返回,然后beanA 初始化完毕,添加beanA到singletonObjects然后返回。

 

© 著作权归作者所有

共有 人打赏支持
边鹏_尛爺鑫
粉丝 29
博文 30
码字总数 24826
作品 0
成都
程序员
私信 提问
Spring基础系列-Spring事务不生效的问题与循环依赖问题

原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9476550.html 一、提出问题   不知道你是否遇到过这样的情况,在ssm框架中开发web引用,或者使用springboot开...

唯一浩哥
2018/08/14
0
0
spring循环依赖的三种方式

1.构造器参数循环依赖 对象间在构造函数中有相互依赖,通过构造函数注入 constructor-arg 启动是会报循环依赖错误 2.setter方式单例,默认方式 spring先通过无参构造方法创建bean,然后通过s...

素雷
2018/08/08
0
0
通过循环依赖问题彻底理解SpringIOC的精华

前言 你可能会有如下问题: 1、想看Spring源码,但是不知道应当如何入手去看,对整个Bean的流程没有概念,碰到相关问题也没有头绪如何下手 2、看过几遍源码,没办法彻底理解,没什么感觉,没...

Java填坑之路
2018/11/19
0
0
SpringFramework核心技术一(IOC:依赖注入)

依赖注入 什么是依赖注入?为什么要有依赖注入? 典型的企业应用程序不包含单个对象(或Spring的说法中的bean)。即使最简单的应用程序也有几个对象一起工作,将最终的结果展示出来的程序作为...

王木东
2018/05/15
0
0
Spring是怎么解决循环依赖的

什么是循环依赖? 循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图: 注意,这里不是函数的循环调用,是对...

Jack1991
2018/04/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java12的新特性

Java语言特性系列 Java5的新特性 Java6的新特性 Java7的新特性 Java8的新特性 Java9的新特性 Java10的新特性 Java11的新特性 Java12的新特性 Java13的新特性 序 本文主要讲述一下Java12的新特...

go4it
17分钟前
3
0
深入解密比Guava Cache更优秀的缓存-Caffeine

1.前言 读这篇文章之前希望你能好好的阅读: 你应该知道的缓存进化史 和 如何优雅的设计和使用缓存? 。这两篇文章主要从一些实战上面去介绍如何去使用缓存。在这两篇文章中我都比较推荐Caffe...

咖啡拿铁的技术分享
19分钟前
1
0
Java B2B2C多用户商城 springcloud架构 --Eureka服务器搭建及配置

第一步,创建一个普通的springboot项目 以下方法都可以快速创建一个boot项目: 1. 浏览器访问http://start.spring.io/,填写信息,下载zip包,加压到你的ide的工作空间直接使用。 2. 使用ide...

明理萝
30分钟前
1
1
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作

· Oracle 撒手,宣布对个人用户 (Personal Users) , Java 8 官方支持时间持续到 2020 年 12 月;对商业用户(Commercial Users),2019 年 1 月之后不再提供免费更新。 · 红帽喊话,计划在...

Java填坑路
33分钟前
0
0
在 Ali Kubernetes 系统中,我们这样实践混沌工程

在传统的软件测试中,我们通常通过一个给定的条件来判断系统的反馈,通过断言来判断是否符合预期,测试条件和结果通常比较明确和固定。而混沌工程,是通过注入一些“不确定”因素,象放进了一...

阿里云官方博客
34分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部