前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring bean循环依赖问题,与解决方案。

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

作者头像
kinbug [进阶者]
发布2019-03-12 14:21:59
1.4K0
发布2019-03-12 14:21:59
举报
文章被收录于专栏:IT进修之路IT进修之路

前言

        我们知道 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类:

代码语言:javascript
复制
public class TestA {
	
	private TestB testB;

	public TestB getTestB() {
		return testB;
	}

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

B类:

代码语言:javascript
复制
public class TestB {
	
	private TestC testC;

	public TestC getTestC() {
		return testC;
	}

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

C类:

代码语言:javascript
复制
public class TestC {
	
	private TestA testA;

	public TestA getTestA() {
		return testA;
	}

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

简单的注入到spring中xml如:

代码语言:javascript
复制
<!-- 循环依赖测试 -->
<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>

测试类:

代码语言:javascript
复制
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项目,运行项目不会报错,但是当你引用的时候,或者运行测试类后发现报错:

代码语言:javascript
复制
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然后返回。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/11/27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档