SpringBoot构造器注入循环依赖及解决
1. 循环依赖是什么?
Bean A 依赖 B,Bean B 依赖 A这种情况下出现循环依赖。
Bean A → Bean B → Bean A
更复杂的间接依赖造成的循环依赖如下。
Bean A → Bean B → Bean C → Bean D → Bean E → Bean A
2. 循环依赖会产生什么结果?
当Spring正在加载所有Bean时,Spring尝试以能正常创建Bean的顺序去创建Bean。
例如,有如下依赖:
Bean A → Bean B → Bean C
Spring先创建beanC,接着创建bean B(将C注入B中),最后创建bean A(将B注入A中)。
但当存在循环依赖时,Spring将无法决定先创建哪个bean。这种情况下,Spring将产生异常BeanCurrentlyInCreationException。
当使用构造器注入时经常会发生循环依赖问题。如果使用其它类型的注入方式能够避免这种问题。
3. 构造器注入循环依赖实例
首先定义两个相互通过构造器注入依赖的bean。
@Component
public class CircularDependencyA {private CircularDependencyB circB;@Autowiredpublic CircularDependencyA(CircularDependencyB circB) {this.circB = circB;}
}
@Component
public class CircularDependencyB {private CircularDependencyA circA;@Autowiredpublic CircularDependencyB(CircularDependencyA circA) {this.circA = circA;}
}
@Configuration
@ComponentScan(basePackages = { "com.baeldung.circulardependency" })
public class TestConfig {
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class CircularDependencyTest {@Testpublic void givenCircularDependency_whenConstructorInjection_thenItFails() {// Empty test; we just want the context to load}
}
运行方法givenCircularDependency_whenConstructorInjection_thenItFails将会产生异常:BeanCurrentlyInCreationException: Error creating bean with name ‘circularDependencyA’:
Requested bean is currently in creation: Is there an unresolvable circular reference?
4.解决方法
处理这种问题目前有如下几种常见方式。
4.1 重新设计
4.2 使用注解 @Lazy
一种最简单的消除循环依赖的方式是通过延迟加载。在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入。
@Component
public class CircularDependencyA {private CircularDependencyB circB;@Autowiredpublic CircularDependencyA(@Lazy CircularDependencyB circB) {this.circB = circB;}
}
4.3 使用Setter/Field注入
Spring文档建议的一种方式是使用setter注入。当依赖最终被使用时才进行注入。对前文的样例代码少做修改,来观察测试效果。
@Component
public class CircularDependencyA {private CircularDependencyB circB;@Autowiredpublic void setCircB(CircularDependencyB circB) {this.circB = circB;}public CircularDependencyB getCircB() {return circB;}
}
@Component
public class CircularDependencyB {private CircularDependencyA circA;private String message = "Hi!";@Autowiredpublic void setCircA(CircularDependencyA circA) {this.circA = circA;}public String getMessage() {return message;}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class CircularDependencyTest {@AutowiredApplicationContext context;@Beanpublic CircularDependencyA getCircularDependencyA() {return new CircularDependencyA();}@Beanpublic CircularDependencyB getCircularDependencyB() {return new CircularDependencyB();}@Testpublic void givenCircularDependency_whenSetterInjection_thenItWorks() {CircularDependencyA circA = context.getBean(CircularDependencyA.class);Assert.assertEquals("Hi!", circA.getCircB().getMessage());}
}
4.4 使用@PostConstruct
@Component
public class CircularDependencyA {@Autowiredprivate CircularDependencyB circB;@PostConstructpublic void init() {circB.setCircA(this);}public CircularDependencyB getCircB() {return circB;}
}
@Component
public class CircularDependencyB {private CircularDependencyA circA;private String message = "Hi!";public void setCircA(CircularDependencyA circA) {this.circA = circA;}public String getMessage() {return message;}
}
4.5 实现ApplicationContextAware与InitializingBean
@Component
public class CircularDependencyA implements ApplicationContextAware, InitializingBean {private CircularDependencyB circB;private ApplicationContext context;public CircularDependencyB getCircB() {return circB;}@Overridepublic void afterPropertiesSet() throws Exception {circB = context.getBean(CircularDependencyB.class);}@Overridepublic void setApplicationContext(final ApplicationContext ctx) throws BeansException {context = ctx;}
}
@Component
public class CircularDependencyB {private CircularDependencyA circA;private String message = "Hi!";@Autowiredpublic void setCircA(CircularDependencyA circA) {this.circA = circA;}public String getMessage() {return message;}
}
5.总结
处理循环依赖有多种方式。首先考虑是否能够通过重新设计依赖来避免循环依赖。如果确实需要循环依赖,那么可以通过前文提到的方式来处理。优先建议使用setter注入来解决。
SpringBoot构造器注入循环依赖及解决相关推荐
- Spring构造器注入循环依赖的解决方案及原理探索
前言 我们都知道Spring解决了Setter注入或者Field注入的循环依赖问题,依靠的是三个Map(earlySingletonObjects.singletonFactories.singlet ...
- Spring-bean的循环依赖以及解决方式___Spring源码初探--Bean的初始化-循环依赖的解决
本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可以应用在我们实际开发项目中. 什么是循环依赖? 怎么检测循环依赖 Spring怎么解决循环依赖 S ...
- Spring循环依赖及其解决方式
部分原文链接:java 循环依赖_Java详解之Spring Bean的循环依赖解决方案_以太创服的博客-CSDN博客 1,什么是循环依赖: 在spring中,对象的创建是交给Spring容器去执行的 ...
- spring循环依赖及解决方法
一.三种循环依赖的情况 ①构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常. ②单例模式下的setter循环依赖:通过& ...
- map 循环_被问到Spring循环依赖怎么解决?秀给面试官看!内附图解
不知道最近有没有被一道Java面试题刷爆朋友圈,Spring框架的循环依赖如何解决.我收到了不少粉丝的提问,在了解到之后,也去网上查询了一些资料,自己也询问了身边的同事,总结出以下几个方面,今天就和我 ...
- spring循环依赖及解决方式_来探究一下Spring 循环依赖的三种方式
引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错.下面说一下Spring是如果解决循环依赖的. 第一种: ...
- spring相互依赖怎么解决_被问到Spring循环依赖怎么解决?秀给面试官看!内附图解...
不知道最近有没有被一道Java面试题刷爆朋友圈,Spring框架的循环依赖如何解决.我收到了不少粉丝的提问,在了解到之后,也去网上查询了一些资料,自己也询问了身边的同事,总结出以下几个方面,今天就和我 ...
- Spring中循环依赖的解决办法
点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 1.什么是循环依赖? 循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方. A类中有一个B类型的成员变量, ...
- 【Spring面试题】循环依赖如何解决?
1.什么是循环依赖 循环依赖指的是两个类中的属性相互依赖对方:例如 A 类中有 B 属性,B 类中有 A属性,从而形成了一个依赖闭环. 2.循环依赖的两种情况及其解决方案 2.1 构造器的循环依赖 这 ...
最新文章
- python async await报错_Python 3.7.7 发布 支持async并await现在为保留关键字
- android 保存流媒体,Android实现使用流媒体播放远程mp3文件的方法
- 编译器会影响编译吗?
- 如何关闭Windows10任务栏里的应用图标
- 苹果CMS小俊XG013主题模板源码
- HTML img 标签的 border 属性
- SQL注入学习part01:(结合sqli-libs学习:1-10关)
- [Python]从哪里开始学习写代码(未完待续)
- LintCode2016年8月8日算法比赛----子树
- java获取classes_一个Java项目布署到weblogic里,听说weblogic会把classes目录打成jar包,怎么获取classes里文件的路径...
- Zabbix 网页端监控工具
- php展厅控制系统,展厅中控系统
- NoteFirst的Word插件(WordAddIn)安装过程中遇到的问题和解决方案
- 测试工具Monitor入门
- 微信HTML5页面设计建议
- 4005. 取石子游戏
- 小程序获取上一个页面或者某个页面内的值
- 华为手机安装Goole play教程及安装包
- mysql分页查询出租房屋信息_分页查询信息(使用jdbc连接mysql数据库实现分页查询任务)...
- oracle 10g与oracle 11g的不同
热门文章
- Easyui datagrid detailview使用
- 如何去除照片中的水印
- cmd 关闭计算机,cmd shutdown命令,立即关机命令shutdown
- android surfaceview 大小,Android设置SurfaceView任意大小、任意位置、保持预览宽高比与屏...
- 非常精美的纸艺术作品欣赏(下篇)
- HP LaserJet Pro P1606dn 激光打印机 - 配置 IP 地址
- Android 手机各大厂商的指纹设置界面
- 最优化的非线性例子集中
- 微信 html tree,微信小程序 tree组件
- Hololens官方第三视角技术