Nodejs nestjs的循环引用问题
Nodejs中nestjs的循环引用问题
我有几个 module ,service 引用结构如下
A -> B -> A. 也就是说 A ,B 有相互引用关系;这样会导致循环引用问题; nestjs 编译会报错;
通过查询,了解到的解决方法有两种;
- 抽离一个 module C ,然后引入 Service A ,B ; 在 A ,B controller 中直接引入 Service C ;那样 service A ,B 就会是单纯业务逻辑,不会引发 circular dependencies
- 是使用 forwardref
这两种方法都可以;但是有点疑问,希望能得到解惑;谢谢了;
方法 1: 会多出一个 module ; 那如果有关联关系的业务实体,是不是都会引发一个新的 module 来避免 circular dependencies
那我是不是可以把所有的 service 集中在一起 Module Common ,然后供 controller 消费,就能避免在 service 中消费其他 service 引发 circular dependencies ;这样的话 Module Common 就变成了垃圾桶了,啥都放在里面;
方法 2: 有可能发生未知错误;不知道引用关系到底是什么样子的;跟 nestjs 的依赖注入 设计有点相反;不太想用
最简单的方法是合并 A 和 B 为一个模块
理论上极少数情况会出现循环引用的情况,如果一旦出现基本说明两个模块耦合严重,这种情况合并就是了,至于你说的方法 1 其实是合并后的抽离可复用代码。
抽一个 C ,然后 A 和 B 的 Service (不是 Controller )都注入 C (不要直接 import ,走 NestJS 的 Injectable ),就像你 Service 会用 HttpService 一样搞
楼上两位朋友说的都对,我再补充一点, 还有一种方法,不引入 service 而是引入 reponstory ,
遇到过这种问题,使用的第一种方案,用 forwardref 我没跑成功。
看你说的只注入 repository ,我想是脱离问题本质了,本来就是想方便复用,这样相当于重写一遍逻辑了(也可以把数据库操作扩充到原有 repository 上,算是复用代码了吧)。
另外你说的抽到 Common 里,那为什么不一开始全写 Common 里,那样模块化就没有意义了,也不循环引用了。
控制反转有两种实现方案:依赖注入和依赖查找。nestjs 采用依赖注入导致模块之间代码耦合严重。本来模块化的意义就是实现代码隔离,但是 nestjs 实际上确是模块之间代码相互引用。因此,在 node 生态中,最便利的是依赖查找方案,可以实现模块之间的完全隔离,也就不会出现类似循环引用的问题,更不需要提出一个中间模块。可以参见 CabloyJS 全栈框架的《 Bean 容器与控制反转》: https://cabloy.com/zh-cn/articles/bean.html
在Node.js中使用NestJS框架时,循环引用是一个常见的问题,特别是在模块和服务之间。循环引用会导致应用程序启动失败,因为NestJS的依赖注入系统无法正确解析依赖关系。
解决方案
-
重新设计模块结构: 最直接的解决方案是重新设计你的模块结构,避免循环引用。确保每个模块只依赖于其他模块的输出,而不是内部实现。
-
使用
forwardRef
: 如果重新设计模块结构不可行,你可以使用forwardRef
来告诉NestJS延迟解析依赖关系。import { Module, forwardRef } from '[@nestjs](/user/nestjs)/common'; import { ServiceA } from './service-a'; import { ServiceB } from './service-b'; [@Module](/user/Module)({ providers: [ ServiceA, { provide: 'ServiceB', useClass: forwardRef(() => ServiceB), }, ], exports: ['ServiceB'], }) export class ModuleA {} [@Module](/user/Module)({ imports: [forwardRef(() => ModuleA)], providers: [ServiceB], }) export class ModuleB {}
-
延迟加载模块: 在某些情况下,你可以通过延迟加载模块来避免循环引用。这可以通过动态导入模块来实现。
async function bootstrap() { const app = await NestFactory.create(AppModule); await app.init(); const moduleB = await import('./module-b.module').then(m => m.ModuleB); app.registerModule(moduleB); await app.listen(3000); } bootstrap();
选择哪种方法取决于你的具体需求和应用程序的复杂性。