热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Spring循环依赖的三种方式(推荐)

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

引言:循环依赖就是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对象实例化之后再设置对象属性的

修改配置文件为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"> 
     
   
  scope="prototype"> 
     
   
  scope="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常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了在使用MSXML解析XML文件时出现DTD禁用问题的解决方案。通过代码示例和错误信息获取方法,解释了默认情况下DTD是禁用的,以及如何启用DTD的方法。此外,还提到了网上关于该问题的信息相对较少,因此本文提供了解决方案以供参考。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • 乐山市计算机学校2017—2018学年度第一学期开学典礼隆重举行
    乐山市计算机学校于2017—2018学年度第一学期举行了隆重的开学典礼,全体教职工和学生参加了此次典礼。乐山市计算机学校自建校以来一直秉承着追求崇高、抓住机遇、回报社会的办学宗旨,取得了累累硕果。在典礼上,常务副校长梁志明发表了致辞,鼓励全体新生用自己的智慧和勤奋去创造优秀的业绩。同时,苏稽镇派出所所长、市计算机学校法制副校长邹学斌提出了关于遵守法律法规和社会公共道德规范、树立自尊、自律、自强意识以及相信和依靠法律的建议,以维护校园秩序的平安和谐。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文介绍了一个免费的asp.net控件,该控件具备数据显示、录入、更新、删除等功能。它比datagrid更易用、更实用,同时具备多种功能,例如属性设置、数据排序、字段类型格式化显示、密码字段支持、图像字段上传和生成缩略图等。此外,它还提供了数据验证、日期选择器、数字选择器等功能,以及防止注入攻击、非本页提交和自动分页技术等安全性和性能优化功能。最后,该控件还支持字段值合计和数据导出功能。总之,该控件功能强大且免费,适用于asp.net开发。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
author-avatar
行玲于諭淑臻
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有