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

如何通过规范的DI方式实例化携带动态参数的构造函数?

针对动态参数服务的DI实现方案

这个场景非常适合使用ModuleRef实现,若服务拆分在独立子模块中,也可搭配懒加载(Lazy Loading)实现,完全符合DI规范,相比手动实例化的方式可维护性更强。

现有手动实例化方案的问题

  • 手动new服务的方式会导致服务内部的其他DI依赖无法被Nest容器自动注入,比如后续OutletService需要依赖HttpService、ConfigService等全局注册的服务时,你需要手动传递所有依赖,维护成本极高
  • 不符合依赖倒置原则,服务之间的耦合度高,不利于单元测试

基于ModuleRef的标准实现方案

核心思路是将所有服务改为标准@Injectable()装饰的可注入类,动态参数通过自定义注入Token传递,调用ModuleRef.create()方法在运行时传入动态参数创建实例,容器会自动解析所有依赖。

第一步:改造服务为标准可注入类

import { Injectable, Inject } from '@nestjs/common';
import type { RequestDTO } from './dto/request.dto';

// 定义自定义注入Token,用于传递动态apiKey
export const API_KEY_TOKEN = Symbol('API_KEY');

@Injectable()
export class OutletService {
  // apiKey通过注入Token获取,不需要手动传入
  constructor(@Inject(API_KEY_TOKEN) private apiKey: string) {}
  // 其他业务逻辑
}

@Injectable()
export class NewService {
  // OutletService由DI容器自动注入,不需要手动new
  constructor(
    @Inject(API_KEY_TOKEN) private apiKey: string,
    private outletService: OutletService
  ) {}

  async triggerBoarding(dto: RequestDTO) {
    // 业务逻辑实现
  }
}

第二步:控制器中通过ModuleRef创建实例

import { Controller, Post, Body, ModuleRef } from '@nestjs/common';
import { NewService, API_KEY_TOKEN } from './new.service';

@Controller()
export class YourController {
  // 注入当前模块的ModuleRef实例
  constructor(private moduleRef: ModuleRef) {}

  @Post()
  public async handleRequest(
    @Body() requestDto: RequestDTO
  ): Promise<void> {
    // 运行时传入动态apiKey,创建NewService实例,容器自动解析所有依赖
    const newService = await this.moduleRef.create(NewService, {
      providers: [
        {
          provide: API_KEY_TOKEN,
          useValue: API_KEYS.get(requestDto.address.country)
        }
      ]
    });
    await newService.triggerBoarding(requestDto);
  }
}

懒加载的适配场景

如果你的NewService和关联服务属于独立的功能模块,不需要在应用启动时就加载,可以先懒加载对应模块,再用子模块的ModuleRef创建实例,适合中大型应用拆分模块、降低启动耗时的场景。如果服务就在当前模块内,不需要懒加载,直接用当前注入的ModuleRef即可。

可选优化方案

如果你的场景中多个服务都需要用到当前请求的apiKey,也可以考虑使用*请求作用域(Request Scoped)*的提供者,但请求作用域会触发依赖链上的所有服务都按请求实例化,有一定性能开销,相比之下ModuleRef.create()的方式更轻量,适合仅少数服务需要动态参数的场景。

内容的提问来源于stack exchange,提问作者styler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:06:06