如何在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'], }; } }
关键修改说明
- 新增
PROMETHEUS_MODULE_OPTIONS令牌,用于在依赖注入中标识配置实例 - forRootAsync不再直接调用useFactory,而是将其注册为配置提供者,由Nest负责注入ConfigService并执行
- metrics持有者通过工厂提供者创建,依赖解析后的配置,实现动态生成
- AppModule的调用代码无需修改,保持原有写法即可
内容的提问来源于stack exchange,提问作者Daniel Gruszczyk
相关产品推荐
相关产品推荐

