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
相关产品推荐
相关产品推荐

