如何直接访问NestJS DI容器并通过ID获取指定服务(非@Injectable类场景)
在NestJS的非@Injectable类中访问DI容器获取指定服务
嘿,从Symfony转NestJS确实会遇到DI使用习惯的小切换,我来帮你梳理怎么实现你要的功能——不管是在可注入类还是非可注入类里,NestJS都支持通过服务ID直接获取容器里的实例!
方法1:全局存储容器实例(最贴近Symfony的直接调用方式)
你可以在应用启动时把容器实例存为全局变量,之后在任何类里直接调用:
首先在main.ts中保存容器引用:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; // 全局变量存储容器实例 export let appContainer; async function bootstrap() { const app = await NestFactory.create(AppModule); // 获取根模块的容器 appContainer = app.select(AppModule).getContainer(); await app.listen(3000); } bootstrap();
然后在你的非@Injectable类中使用:
import { appContainer } from './main'; export class StatefulCruncherClass { constructor(private dataToCrunch: any) {} async crunch() { if (this.dataToCrunch.isObject) { // 通过服务ID获取实例(支持字符串ID或类引用) const objectsCruncher = appContainer.get('ObjectsCruncher'); return objectsCruncher.crunch(this); } else { const arrayCruncher = appContainer.get('ArrayCruncher'); return arrayCruncher.crunch(this); } } }
小提示:如果你的服务是
@Injectable()装饰的类,推荐用类引用代替字符串ID(比如appContainer.get(ObjectsCruncher)),这样能获得TypeScript的类型安全检查,避免拼写错误。
方法2:通过ModuleRef传递容器(更可控的方式)
如果你不想用全局变量,也可以借助NestJS的ModuleRef(它本身需要注入到可注入类中),在创建非可注入类实例时把ModuleRef传进去:
首先在某个可注入服务中注入ModuleRef:
import { Injectable, ModuleRef } from '@nestjs/common'; @Injectable() export class CruncherFactory { constructor(private moduleRef: ModuleRef) {} // 创建非可注入类实例时传入ModuleRef createStatefulCruncher(data: any) { return new StatefulCruncherClass(data, this.moduleRef); } }
修改你的StatefulCruncherClass来接收ModuleRef:
import { ModuleRef } from '@nestjs/common'; export class StatefulCruncherClass { constructor(private dataToCrunch: any, private moduleRef: ModuleRef) {} async crunch() { if (this.dataToCrunch.isObject) { const objectsCruncher = this.moduleRef.get('ObjectsCruncher'); return objectsCruncher.crunch(this); } else { const arrayCruncher = this.moduleRef.get('ArrayCruncher'); return arrayCruncher.crunch(this); } } }
额外注意事项
- 如果你的服务在子模块中,需要指定模块范围:比如
appContainer.select(SubModule).get('ObjectsCruncher'),或者给get方法加参数{ strict: false }来允许跨模块获取服务 - 全局容器方式要确保在应用完全启动后再调用,避免容器未初始化完成的问题
内容的提问来源于stack exchange,提问作者Tesmen
相关产品推荐
相关产品推荐

