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

NestJS中如何正确注入类并在方法调用时每次生成新实例

嘿,这个需求我太熟了!在NestJS里默认的依赖注入都是单例模式,但要每次调用doStuff方法都生成SomeClass的新实例,有几种实用的方案,我给你挨个说清楚:

方案一:利用请求作用域(Request Scoped)自动生成新实例

NestJS里可以给类设置请求作用域,这样每次HTTP请求进来时,都会创建这个类的新实例。你只需要给SomeClass加上@Injectable({ scope: Scope.REQUEST }),然后在SomeService里正常注入它就行:

import { Injectable, Scope } from '@nestjs/common';

@Injectable({ scope: Scope.REQUEST })
class SomeClass {
  constructor() {
    console.log('新的SomeClass实例已创建');
  }
}

@Injectable()
class SomeService {
  constructor(private readonly someClass: SomeClass) {}

  async doStuff() {
    // 每次调用doStuff时,this.someClass都是当前请求对应的新实例
    // 注意:如果你的SomeService是单例,注入请求作用域的类会自动把SomeService也变成请求作用域
  }
}

注意点:

  • 这个方案适合HTTP请求场景,如果是定时任务、CLI命令这类无请求的场景,就不适用了。
  • 请求作用域会带来一定性能开销,因为每次请求都要创建实例,需要根据你的业务场景权衡。

方案二:通过工厂提供者手动控制实例创建

如果你不想把SomeClass变成请求作用域,或者需要在非请求场景下生成新实例,可以用工厂提供者来封装实例创建逻辑。在模块里配置一个工厂,然后在SomeService里注入这个工厂函数,每次调用函数就得到新实例:

import { Injectable, Module, Inject } from '@nestjs/common';

class SomeClass {
  constructor() {
    console.log('新的SomeClass实例已创建');
  }
}

@Injectable()
class SomeService {
  constructor(
    // 注入我们定义的工厂函数
    @Inject('SOME_CLASS_FACTORY') private readonly someClassFactory: () => SomeClass,
  ) {}

  async doStuff() {
    // 每次调用都会生成新的SomeClass实例
    const newInstance = this.someClassFactory();
  }
}

@Module({
  providers: [
    SomeService,
    {
      provide: 'SOME_CLASS_FACTORY',
      useFactory: () => {
        // 返回一个创建实例的函数
        return () => new SomeClass();
      },
    },
  ],
})
export class AppModule {}

优势:

  • SomeService可以保持单例模式,不会被强制变成请求作用域。
  • 完全手动控制实例创建时机,灵活性很高。

方案三:用ModuleRef动态创建带依赖的实例

如果SomeClass本身还有其他依赖需要注入(比如另一个服务),上面的工厂方式就没法自动处理依赖了。这时候可以用Nest的ModuleRef来动态创建实例,它会自动帮你处理SomeClass的依赖注入:

import { Injectable, ModuleRef } from '@nestjs/common';

// 假设SomeClass有依赖
@Injectable()
class SomeDependency {}

@Injectable()
class SomeClass {
  constructor(private readonly dep: SomeDependency) {}
}

@Injectable()
class SomeService {
  constructor(private readonly moduleRef: ModuleRef) {}

  async doStuff() {
    // 每次调用都会创建带完整依赖的新SomeClass实例
    const newInstance = await this.moduleRef.create(SomeClass);
  }
}

这个方案是最灵活的,不管SomeClass有没有依赖,也不管场景是不是HTTP请求,都能生成新实例。


总结一下:

  • 如果你是HTTP请求场景,优先考虑请求作用域,代码最简单。
  • 如果需要保持服务单例,或者非请求场景,用工厂提供者。
  • 如果SomeClass有依赖要注入,选ModuleRef的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:12:30