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

如何在NestJS动态模块的forRootAsync中正确调用useFactory?

解决NestJS动态模块forRootAsync无法获取ConfigService的问题

你的核心问题在于直接在forRootAsync方法内调用useFactory,没有通过Nest的依赖注入容器处理依赖参数。Nest的异步模块配置需要让框架来管理依赖注入流程,而不是手动调用useFactory(此时容器尚未初始化inject中声明的服务,比如ConfigService)。

解决方案

重新实现PrometheusModule的forRootAsync方法,通过注册配置提供者让Nest处理依赖注入,再基于解析后的配置动态生成模块内容:

import { Module, DynamicModule, ModuleMetadata } from '@nestjs/common';
import * as client from 'prom-client';

export interface PrometheusModuleOpts {
  enableMetrics: boolean;
  counters: client.CounterConfiguration<string>[];
  histograms: client.HistogramConfiguration<string>[];
}

export interface PrometheusModuleAsyncOpts extends Pick<ModuleMetadata, 'imports'> {
  useFactory: (...args: any[]) => Promise<PrometheusModuleOpts> | PrometheusModuleOpts;
  inject: any[];
}

const defaultOpts: PrometheusModuleOpts = {
  enableMetrics: false,
  counters: [],
  histograms: [],
};

// 定义配置令牌,用于依赖注入标识
export const PROMETHEUS_MODULE_OPTIONS = Symbol('PROMETHEUS_MODULE_OPTIONS');

@Global()
@Module({})
export class PrometheusModule {
  static forRoot(opts: PrometheusModuleOpts = defaultOpts): DynamicModule {
    // 静态配置下直接生成metrics实例
    const metricsHolder = {};
    if (opts.enableMetrics) {
      opts.counters.forEach(counter => {
        metricsHolder[counter.name] = new client.Counter(counter);
      });
      opts.histograms.forEach(histogram => {
        metricsHolder[histogram.name] = new client.Histogram(histogram);
      });
    }

    return {
      module: PrometheusModule,
      providers: [
        {
          provide: PROMETHEUS_MODULE_OPTIONS,
          useValue: opts,
        },
        {
          provide: 'METRICS_HOLDER',
          useValue: metricsHolder,
        },
      ],
      exports: [PROMETHEUS_MODULE_OPTIONS, 'METRICS_HOLDER'],
    };
  }

  static forRootAsync(asyncOpts: PrometheusModuleAsyncOpts): DynamicModule {
    // 注册配置提供者,让Nest负责注入依赖并执行useFactory
    const optionsProvider = {
      provide: PROMETHEUS_MODULE_OPTIONS,
      useFactory: asyncOpts.useFactory,
      inject: asyncOpts.inject,
    };

    // 动态生成metrics持有者,依赖解析后的配置
    const metricsHolderProvider = {
      provide: 'METRICS_HOLDER',
      useFactory: (opts: PrometheusModuleOpts) => {
        const holder = {};
        if (opts.enableMetrics) {
          opts.counters.forEach(counter => {
            holder[counter.name] = new client.Counter(counter);
          });
          opts.histograms.forEach(histogram => {
            holder[histogram.name] = new client.Histogram(histogram);
          });
        }
        return holder;
      },
      inject: [PROMETHEUS_MODULE_OPTIONS],
    };

    return {
      module: PrometheusModule,
      imports: asyncOpts.imports || [],
      providers: [optionsProvider, metricsHolderProvider],
      exports: [PROMETHEUS_MODULE_OPTIONS, 'METRICS_HOLDER'],
    };
  }
}

关键修改说明

  1. 新增PROMETHEUS_MODULE_OPTIONS令牌,用于在依赖注入中标识配置实例
  2. forRootAsync不再直接调用useFactory,而是将其注册为配置提供者,由Nest负责注入ConfigService并执行
  3. metrics持有者通过工厂提供者创建,依赖解析后的配置,实现动态生成
  4. AppModule的调用代码无需修改,保持原有写法即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:17:27