背景
最近项目需要到一个基于事件驱动的一些业务模块,就封装一下类似@nestjs/bull一样的API去进行事件注册和触发,减少了一定的代码量。
通过Nest Core的功能去完成全局扫描metadata
通过@nestjs/core
,我们可以找到相应框架实现的功能和工具,去完成我们需要写业务逻辑前的工作
DiscoveryService —— 扫描所有app module注册到的controllers和services
首先我们需要扫描所有的controller和service,通过DiscoveryService
可以实现,伪代码如下:
// explorer.service.ts
import {
Injectable } from '@nestjs/common';
import {
DiscoveryService} from '@nestjs/core';
@Injectable()
export class AccessorService {
constructor(
private readonly discoveryService: DiscoveryService
) {
}
run() {
const providers = this.discoveryService.getProviders();
const controllers = this.discoveryService.getControllers();
// ...
}
}
那么调用这些方法返回的是什么?从类型定义上看,是一个InstanceWrapper
,主要是在nestjs对controller和service注入到module的时候,对class实例后的对象封装了一层wrapper
MetadataScanner —— 扫描出有Metadata的类方法
然后再去遍历我们定义的decorator和metadata,这时候就需要MetadataScanner
// explorer.service.ts
import {
Injectable } from '@nestjs/common';
import {
DiscoveryService} from '@nestjs/core';
import {
MetadataScanner } from '@nestjs/core/metadata-scanner';
@Injectable()
export class AccessorService {
constructor(
private readonly discoveryService: DiscoveryService,
private readonly metadataScanner: MetadataScanner,
) {
}
run() {
const providers = this.discoveryService.getProviders();
const controllers = this.discoveryService.getControllers();
[...providers, ...controllers]
.filter(wrapper => wrapper.isDependencyTreeStatic())
.filter(wrapper => wrapper.instance)
.forEach((wrapper: InstanceWrapper) => {
const {
instance } = wrapper;
const prototype = Object.getPrototypeOf(instance);
this.metadataScanner.scanFromPrototype(
instance,
prototype,
(methodKey: string) => {