如何注入循环引用的工厂提供者?NestJS模块实例创建失败
NestJS循环依赖导致模块实例无法创建的问题及解决请求
文件夹结构
. ├── libs/ │ └── dma/ │ ├── client/ │ │ ├── client.module.ts │ │ └── client.service.ts │ ├── cmts/ │ │ ├── cmts.module.ts │ │ └── cmts.service.ts │ └── dma.module.ts └── src/ ├── app.module.ts └── app.service.ts
模块结构

源代码
~/src/app.service.ts
@Injectable() export class AppService { constructor(private readonly cmtsService: CmtsService) {} }
~/src/app.module.ts
@Module({ imports: [ DmaModule.forRootAsync({ useFactory: () => ({ dmaHost: 'DMA_HOST', superadminUsername: 'DMA_SUPERADMIN_USERNAME', superadminPassword: 'DMA_SUPERADMIN_PASSWORD', }), })], providers: [AppService] }) class AppModule{}
~/libs/dma/dma.module.ts
export interface DmaModuleProps { dmaHost: string superadminUsername: string superadminPassword: string } export interface RootAsyncOptions { useFactory: (...args: any[]) => DmaModuleProps } @Module({ imports: [CmtsModule], providers: [], exports: [CmtsModule], }) export class DmaModule{ static forRootAsync(options: RootAsyncOptions): DynamicModule { const DmaOptionsFactoryProvider: FactoryProvider = { provide: 'DMA_OPTIONS', useFactory: options.useFactory, } return { module: DmaModule, providers: [DmaOptionsFactoryProvider], exports: [DmaOptionsFactoryProvider], } } }
~/libs/dma/client/client.module.ts
@Module({ imports: [DmaModule], providers: [ClientService], exports: [ClientService], }) export class ClientModule{}
~/libs/dma/client/client.service.ts
@Injectable() export class ClientService { constructor( @Inject('DMA_OPTIONS') private readonly dmaProps: DmaModuleProps, ) {} }
~/libs/dma/cmts/cmts.module.ts
@Module({ imports: [ClientModule], providers: [CmtsService], exports: [CmtsService] }) export class CmtsModule {}
~/libs/dma/cmts/cmts.service.ts
@Injectable() export class CmtsService { constructor(private readonly clientService: ClientService) {} }
报错信息
[Nest] 642956 - 07/15/2024, 9:47:12 PM ERROR [ExceptionHandler] Nest无法创建ClientModule实例。 ClientModule的"imports"数组中索引为[0]的模块未定义。 可能的原因: - 模块之间存在循环依赖。使用forwardRef()避免此问题。详情请见:https://docs.nestjs.com/fundamentals/circular-dependency - 索引为[0]的模块类型为"undefined"。检查你的导入语句和模块类型。 作用域 [AppModule -> DmaModule -> CmtsModule]
解决方法
问题核心是模块循环依赖:DmaModule 导入 CmtsModule,CmtsModule 导入 ClientModule,ClientModule 又导入 DmaModule,形成闭环。同时动态模块的导出逻辑存在缺陷,导致依赖解析失败。
步骤1:用forwardRef()打破循环依赖
在循环引用的模块导入处使用forwardRef()包装,让NestJS延迟解析模块:
- 修改
ClientModule:
// ~/libs/dma/client/client.module.ts import { forwardRef, Module } from '@nestjs/common'; import { DmaModule } from '../dma.module'; import { ClientService } from './client.service'; @Module({ imports: [forwardRef(() => DmaModule)], providers: [ClientService], exports: [ClientService], }) export class ClientModule{}
- 修改
DmaModule:
// ~/libs/dma/dma.module.ts import { forwardRef, Module } from '@nestjs/common'; import { CmtsModule } from './cmts/cmts.module'; @Module({ imports: [forwardRef(() => CmtsModule)], providers: [], exports: [CmtsModule], }) export class DmaModule{ // 原有forRootAsync逻辑保留 }
步骤2:调整动态模块导出逻辑
确保DmaModule的动态模块正确导入依赖并导出所需提供者:
// ~/libs/dma/dma.module.ts import { forwardRef, Module, DynamicModule } from '@nestjs/common'; import { CmtsModule } from './cmts/cmts.module'; // 原有接口定义保留 @Module({ imports: [forwardRef(() => CmtsModule)], providers: [], exports: [CmtsModule], }) export class DmaModule{ static forRootAsync(options: RootAsyncOptions): DynamicModule { const DmaOptionsFactoryProvider = { provide: 'DMA_OPTIONS', useFactory: options.useFactory, }; return { module: DmaModule, imports: [forwardRef(() => CmtsModule)], providers: [DmaOptionsFactoryProvider], exports: [DmaOptionsFactoryProvider, CmtsModule], }; } }
步骤3:验证导入路径
确认所有模块的导入路径拼写正确,避免因路径错误导致模块未定义。
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

