You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何注入循环引用的工厂提供者?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延迟解析模块:

  1. 修改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{}
  1. 修改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-

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:12:33