千家信息网

Spring解决循环依赖的方式有哪些

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,小编给大家分享一下Spring解决循环依赖的方式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!循环依赖就是N个类中循
千家信息网最后更新 2026年11月03日Spring解决循环依赖的方式有哪些

小编给大家分享一下Spring解决循环依赖的方式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错。

Spring是如果解决循环依赖的。

第一种:构造器参数循环依赖

Spring容器会将每一个正在创建的Bean 标识符放在一个"当前创建Bean池"中,Bean标识符在创建过程中将一直保持在这个池中。

因此如果在创建Bean过程中发现自己已经在"当前创建Bean池"里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从"当前创建Bean池"中清除掉。

首先我们先初始化三个Bean。

public class StudentA {      private StudentB studentB ;      public void setStudentB(StudentB studentB) {          this.studentB = studentB;      }      public StudentA() {      }      public StudentA(StudentB studentB) {          this.studentB = studentB;      }  }
public class StudentB {      private StudentC studentC ;      public void setStudentC(StudentC studentC) {          this.studentC = studentC;      }      public StudentB() {      }      public StudentB(StudentC studentC) {          this.studentC = studentC;      }  }
public class StudentC {      private StudentA studentA ;      public void setStudentA(StudentA studentA) {          this.studentA = studentA;      }      public StudentC() {      }      public StudentC(StudentA studentA) {          this.studentA = studentA;      }  }

OK,上面是很基本的3个类,StudentA有参构造是StudentB。StudentB的有参构造是StudentC,StudentC的有参构造是StudentA ,这样就产生了一个循环依赖的情况。

我们都把这三个Bean交给 Spring 管理,并用有参构造实例化。

                      

下面是测试类:

public class Test {      public static void main(String[] args) {          ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");          //System.out.println(context.getBean("a", StudentA.class));      }  }

执行结果报错信息为:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:    Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?

如果大家理解开头那句话的话,这个报错应该不惊讶,Spring容器先创建单例StudentA,StudentA依赖StudentB,然后将A放在"当前创建Bean池"中。

此时创建StudentB,StudentB依赖StudentC ,然后将B放在"当前创建Bean池"中,此时创建StudentC,StudentC又依赖StudentA。

但是,此时Student已经在池中,所以会报错,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,初始化完的Bean会从池中移除。

第二种:setter方式单例,默认方式

如果要说setter方式注入的话,我们最好先看一张Spring中Bean实例化的图

如图中前两步骤得知:Spring是先将Bean对象实例化之后再设置对象属性的,Spring 中的 bean 为什么默认单例, 这篇建议大家看下。

关注微信公众号:Java技术栈,在后台回复:spring,可以获取我整理的 N 篇最新 Spring 教程,都是干货。

修改配置文件为set方式注入

                        

下面是测试类:

public class Test {      public static void main(String[] args) {         ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");          System.out.println(context.getBean("a", StudentA.class));      }  }

打印结果为:

com.zfx.student.StudentA@1fbfd6

为什么用set方式就不报错了呢 ?

我们结合上面那张图看,Spring先是用构造实例化Bean对象 ,此时 Spring 会将这个实例化结束的对象放到一个Map中,并且 Spring 提供了获取这个未设置属性的实例化对象引用的方法。

结合我们的实例来看,当Spring实例化了StudentA、StudentB、StudentC后,紧接着会去设置对象的属性,此时StudentA依赖StudentB,就会去Map中取出存在里面的单例StudentB对象,以此类推,不会出来循环的问题喽、

下面是Spring源码中的实现方法。以下的源码在Spring的Bean包中的DefaultSingletonBeanRegistry.java类中

/** Cache of singleton objects: bean name --> bean instance(缓存单例实例化对象的Map集合) */  private final Map singletonObjects = new ConcurrentHashMap(64);  /** Cache of singleton factories: bean name --> ObjectFactory(单例的工厂Bean缓存集合) */  private final Map singletonFactories = new HashMap(16);  /** Cache of early singleton objects: bean name --> bean instance(早期的单身对象缓存集合) */  private final Map earlySingletonObjects = new HashMap(16);  /** Set of registered singletons, containing the bean names in registration order(单例的实例化对象名称集合) */  private final Set registeredSingletons = new LinkedHashSet(64);  /**   * 添加单例实例   * 解决循环引用的问题   * Add the given singleton factory for building the specified singleton   * if necessary.   * 

To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object */ protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }

第三种:setter方式原型,prototype

修改配置文件为:

                      

scope="prototype" 意思是 每次请求都会创建一个实例对象。

两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

测试用例:

public class Test {      public static void main(String[] args) {          ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");          //此时必须要获取Spring管理的实例,因为现在scope="prototype" 只有请求获取的时候才会实例化对象          System.out.println(context.getBean("a", StudentA.class));      }  }

打印结果:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:      Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?

为什么原型模式就报错了呢 ?

对于"prototype"作用域Bean,Spring容器无法完成依赖注入,因为"prototype"作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

以上是"Spring解决循环依赖的方式有哪些"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

实例 对象 循环 方式 作用 容器 属性 篇文章 缓存 测试 三个 内容 原型 文件 方法 标识 标识符 源码 状态 结果 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海睿民互联网科技有限公司 互联网络科技有限公司 华中科技有哪些互联网大佬 深圳国际航运科技和互联网 广州恒生互联网科技有限 湖北码尼互联网科技有限公司电话 互联网科技商业 苏州铭阳互联网科技有限公司 互联网保险科技创业 天津腾达互联网科技有限公司 互联网科技和法律行业 四川慕妮娅互联网科技有限公司 互联网金融科技名词解释 工业互联网展湾科技股份有限公司 互联网科技资金流入 信承诺互联网科技有限公司 互联网科技平台产品运营 互联网科技机房 互联网科技博主张洲 青岛易易互联网科技 安徽鑫晟辉互联网科技 腾讯科技 互联网女皇 互联网汽车科技小镇 深圳前海聚择互联网科技有限公司 深圳国际航运科技和互联网 宁波青枫互联网科技有限公司 互联网科技热点资讯 互联网对科技的发展 崇明区互联网教育科技诚信经营 河南住房之家互联网科技
0