NestJS 模块参考
Nest提供了一个ModuleRef类来导航到内部提供者列表,并使用注入令牌作为查找键名来获取一个引用。ModuleRef类也提供了一个动态实例化静态和范围的提供者的方法。ModuleRef可以通过常规方法注入到类中:
cats.service.ts
@Injectable()
export class CatsService {
constructor(private moduleRef: ModuleRef) {}
}
ModuleRef从@nestjs/core中引入。
获取实例
ModuleRef实例(下文称为模块引用) 拥有get()方法。该方法获取一个提供者,控制器或者通过注入令牌/类名获取一个在当前模块中可注入对象(例如守卫或拦截器等)。
cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private service: Service;
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
this.service = this.moduleRef.get(Service);
}
}
不能通过get()方法获取一个范围的提供者(暂态的或者请求范围的)。要使用下列的技术,参考这里了解更多控制范围。
要从全局上下文获取一个提供者(例如,如果提供者在不同模块中注入),向get()的第二个参数传递{ strict: false }选项。
this.moduleRef.get(Service, { strict: false });
处理范围提供者
要动态处理一个范围提供者(瞬态的或请求范围的),使用resolve()方法并将提供者的注入令牌作为参数提供给方法。
cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private transientService: TransientService;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.transientService = await this.moduleRef.resolve(TransientService);
}
}
resolve()方法从其自身的注入容器树返回一个提供者的唯一实例。每个子树都有一个独一无二的上下文引用。因此如果你调用该方法一次以上并进行引用比较的话,结果是不同的。
cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService),
this.moduleRef.resolve(TransientService),
]);
console.log(transientServices[0] === transientServices[1]); // false
}
}
要在不同的resolve()调用之间产生一个单例,并保证他们共享同样生成的DI容器子树,向resolve()方法传递一个上下文引用,使用ContextIdFactory类来生成上下文引用。该类提供了一个create()方法,返回一个合适的独一无二的引用。
cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const contextId = ContextIdFactory.create();
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService, contextId),
this.moduleRef.resolve(TransientService, contextId),
]);
console.log(transientServices[0] === transientServices[1]); // true
}
}
ContextIdFactory类从@nestjs/core包中引入。
注册REQUEST提供者
Manually generated context identifiers (with ContextIdFactory.create()) represent DI sub-trees in which REQUEST provider is undefined as they are not instantiated and managed by the Nest dependency injection system.
To register a custom REQUEST object for a manually created DI sub-tree, use the ModuleRef#registerRequestByContextId() method, as follows:
const contextId = ContextIdFactory.create();
this.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);
获取当前子树
有时,也需要在请求上下文中获取一个请求范围提供者的实例。例如,CatsService是请求范围的,要获取的CatsRepository实例也被标识为请求范围。要分享同一个注入容器子树,你需要获取当前上下文引用而不是生成一个新的(像前面的ContextIdFactory.create()函数)。使用@Inject()来获取当前的请求对象。
cats.service.ts
@Injectable()
export class CatsService {
constructor(
@Inject(REQUEST) private request: Record<string, unknown>,
) {}
}
从这里了解更多请求提供者
使用ContextIdFactory类的getByRequest()方法来基于请求对象创建一个上下文id 并传递resolve()调用:
const contextId = ContextIdFactory.getByRequest(this.request);
const catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);
动态实例化自定义类
要动态实例化一个之前未注册的类作为提供者,使用模块引用的create()方法。
cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private catsFactory: CatsFactory;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.catsFactory = await this.moduleRef.create(CatsFactory);
}
}
该技术允许你在框架容器之外偶然实例化一个不同的类。
更多建议: