登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
广播
Follow
关于
博客
发1篇日志+1圆
记录
发1条记录+2圆币
发帖说明
VIP申请
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
VIP申请
VIP网盘
网盘
联系我们
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
浅谈循环依赖
浅谈循环依赖
[ 复制链接 ]
僚娥
2025-6-9 08:54:36
说明
循环依赖是一个大家讨论很多的话题,它更多是一个工程上的问题而不是技术问题,我们需要首先有一定的认知:
如同两个人相互帮忙,两个类之间你调用我的,我调用你的是很正常也很自然的需求模型。
单一依赖确实有好处,改动一个最顶层类时不需要在意对底部类的影响,但是从本来就自然的模型非要理顺的话就需要额外付出代价,例如额外的拆分类。
循环依赖可以分这几种:
从小的来说是类之间的相互引用。
再大一点的来说是同一个项目下不同模块之间的引用。
再再大一点的来说涉及到微服务或不同类库之间引用。
对于微服务级别或是模块级别的引用来说解决循环依赖是有必要的,因为这可能牵扯到不同人分工协作的问题,而类之间尤其是同一模块下的类之间是否禁止循环依赖实际上是有争议的,本文只讨论同一模块下的类之间的循环引用。
一些解决循环依赖的方法类似@Lazy、getBean等实际上解决的不是循环依赖,而是解决的springboot启动时的循环依赖检测,但本质上它们还是相互引用,所以这里不讨论这些方法,只讨论拆分类的方法。
个人目前比较认同的是同一个人写的同一个模块下的功能是可以循环依赖的,增加额外的拆分类反而会增加复杂度及影响效率,但springboot 2.6版本之后默认禁止了循环依赖,所以个人也在思考,如果想要拆分的化要怎么拆分,目前总结了如下两种不同类型的循环引用拆分示例。
示例
情形一
最常见的老师、学生这种或是主表、子表相互关联的:
@Component
public class Teacher {
@Autowired
private Student student;
public void method() {
//获取某教师下学生类别
List<String> students = student.getStudentsByTeacher("xxx");
System.out.println(students);
}
}
复制代码
@Component
public class Student {
@Autowired
private Teacher teacher;
public void method() {
//获取学生归属的教师
String teacherStr = teacher.getTeacherByStudent("xxx");
System.out.println(teacherStr);
}
}
复制代码
这种拆分比较简单,类似数据库多对多的中间表,我们也创建一个中间类,然后Teacher和Student类不要依赖彼此,直接抽取方法到中间类中或是都引用中间类:
@Component
public class TeacherStudent {
@Autowired
private Teacher teacher;
@Autowired
private Student student;
public void method1() {
//获取某教师下学生类别
List<String> students = student.getStudentsByTeacher("xxx");
System.out.println(students);
}
public void method2() {
//获取学生归属的教师
String teacherStr = teacher.getTeacherByStudent("xxx");
System.out.println(teacherStr);
}
}
复制代码
情形二
另一种常用的场景是引用第三方类库A,然后在配置类B中用@Bean来实例化,而类A是通过读取数据库中的配置(通过类C)来组装参数,而当数据库配置变更时(类C中更新),由于参数变化同时也要重置类A实例,我们在集成微信、钉钉等SDK时会经常遇到此情况,如果直接按照此逻辑写的话,就是下述的代码:
//B本身是个配置类
@Configuration
class B {
@Autowired
private C c;
@Bean
public A init(){
A a = new A();
//引用c的数据库中数据来组装成A实例
a.setProp(c.getProp());
return a;
}
}
复制代码
@Component
class C {
@Autowired
private A a;
public void update(){
//修改数据库相关后,又来重置A实例
a.reset();
}
}
复制代码
此情况下最主要的耦合就是类A需要类C的数据来作为配置项,所以把这个耦合独立出来,而类B中去除类C的引用,仅仅是生成类A的bean:
//用@PostConstruct
@Component
public class D {
@Autowired
private A a;
@Autowired
private C c;
@PostConstruct
public void init(){
a.setProp(c.getProp());
}
}
//或是@Autowired注解到方法上
@Component
public class D {
@Autowired
public void init(A a, C c) {
a.setProp(c.getProp());
}
}
复制代码
虽然从需求上类A依赖类C,但本质上类A并不需要依赖任何类,和第一种情况不同的是类A是一个第三方的类库,我们无法修改其引用及方法,而其本身并不是个bean,需要我们额外去操作。
结果
上述的情况都是额外增加一个拆分类来处理,这样无形中增加了代码量,尤其是第一种情形太常见了,除非是项目初始时就规定好禁止service层互相调用,而是单独再划分一层来处理(类似阿里的manager层),否则的话个人宁愿用@Lazy来解决掉循环依赖的报错。
解决循环依赖上述同模块内的相对简单些,只是增加代码量而已,当涉及到模块或微服务时,则完全不一样,要考虑业务逻辑及架构等一系列问题,感觉很是麻烦。
以上只是个人见解,有更好的观点可发到评论区一起讨论下。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
浅谈
循环
依赖
相关帖子
Python循环语句
[浅谈数据结构] 浅谈树状数组
浅谈后缀自动机
MAVEN构建分离依赖JAR
浅谈C++ const
浅谈图论算法——图的连通性
浅谈故障复盘
shell编程技巧——循环逻辑中使用变量引用方式注意事项
WPF依赖属性学习
【EF Core】实体类的依赖注入
vip免费申请,1年只需15美金$
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
安全
Python循环语句
0
950
准挝
2025-07-31
业界
[浅谈数据结构] 浅谈树状数组
0
654
琶轮
2025-07-31
业界
浅谈后缀自动机
0
330
忿惺噱
2025-08-01
业界
MAVEN构建分离依赖JAR
0
600
森萌黠
2025-08-08
业界
浅谈C++ const
0
376
姘轻拎
2025-08-11
业界
浅谈图论算法——图的连通性
0
79
钱匾
2025-08-20
科技
浅谈故障复盘
0
614
艾晓梅
2025-08-22
安全
shell编程技巧——循环逻辑中使用变量引用方式注意事项
0
671
恐肩
2025-09-03
业界
WPF依赖属性学习
0
111
诉称
2025-09-04
业界
【EF Core】实体类的依赖注入
0
999
笃迩讦
2025-09-06
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
签约作者
程序园优秀签约作者
发帖
僚娥
2025-6-9 08:54:36
关注
0
粉丝关注
12
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9984
黎瑞芝
9990
杭环
9988
4
凶契帽
9988
5
氛疵
9988
6
猷咎
9986
7
里豳朝
9986
8
肿圬后
9986
9
蝓俟佐
9984
10
虽裘侪
9984
查看更多