Fundamentals
发现服务
了解如何使用 DiscoveryService 在运行时动态发现和检索应用程序中的提供者、控制器和模块
发现服务
有时,您可能需要在运行时检索有关已注册的提供者、控制器或模块的信息。DiscoveryService 提供了一个 API 来查询这些信息。
开始使用
要启用 DiscoveryService,请将其导入到您的模块中:
@@filename(app.module)
import { Module } from '@nestjs/common';
import { DiscoveryModule } from '@nestjs/core';
@Module({
imports: [DiscoveryModule],
})
export class AppModule {}
提示 DiscoveryModule 是从 @nestjs/core 包导出的。
现在您可以在任何类中注入 DiscoveryService:
@@filename()
export class ExampleProvider {
constructor(private discoveryService: DiscoveryService) {}
}
@@switch
export class ExampleProvider {
constructor(discoveryService) {
this.discoveryService = discoveryService;
}
}
检索实例
要检索已注册的提供者和控制器,请使用 getProviders() 和 getControllers() 方法。
@@filename()
getProviders(): InstanceWrapper[];
getControllers(): InstanceWrapper[];
@@switch
getProviders();
getControllers();
这两个方法都返回 InstanceWrapper[]。InstanceWrapper 是一个包装器,它保存有关实例的信息,如:
name- 类名metatype- 类引用instance- 在这种情况下,实例化的实例(对于单例作用域的提供者,它将始终是null)isResolved- 指示提供者是否已实例化scope- 提供者的作用域durable- 指示提供者是否持久host- 提供者所属的模块
提示 InstanceWrapper 是从 @nestjs/core 包导出的。
例如:
@@filename()
export class ExampleProvider implements OnModuleInit {
constructor(private discoveryService: DiscoveryService) {}
onModuleInit() {
const providers = this.discoveryService.getProviders();
const controllers = this.discoveryService.getControllers();
// 查找特定的提供者
const exampleProvider = providers.find(
wrapper => wrapper.name === 'ExampleProvider'
);
console.log('ExampleProvider instance:', exampleProvider.instance);
}
}
@@switch
export class ExampleProvider {
constructor(discoveryService) {
this.discoveryService = discoveryService;
}
onModuleInit() {
const providers = this.discoveryService.getProviders();
const controllers = this.discoveryService.getControllers();
// 查找特定的提供者
const exampleProvider = providers.find(
wrapper => wrapper.name === 'ExampleProvider'
);
console.log('ExampleProvider instance:', exampleProvider.instance);
}
}
过滤结果
getProviders() 和 getControllers() 方法接受一个可选的选项对象,允许您过滤结果:
@@filename()
interface DiscoveryOptions {
metadataKey?: string | symbol;
filter?: (wrapper: InstanceWrapper) => boolean;
include?: Function[];
}
@@switch
interface DiscoveryOptions {
metadataKey;
filter;
include;
}
metadataKey- 元数据键,用于过滤具有特定元数据的实例filter- 一个函数,用于过滤实例包装器include- 一个模块数组,用于仅包含来自特定模块的实例
例如,要获取所有具有 @Injectable() 装饰器的提供者:
@@filename()
const injectableProviders = this.discoveryService.getProviders({
filter: (wrapper) => wrapper.metatype && Reflect.hasMetadata('__injectable__', wrapper.metatype)
});
@@switch
const injectableProviders = this.discoveryService.getProviders({
filter: (wrapper) => wrapper.metatype && Reflect.hasMetadata('__injectable__', wrapper.metatype)
});
或者,要获取来自特定模块的所有控制器:
@@filename()
const appControllers = this.discoveryService.getControllers({
include: [AppModule]
});
@@switch
const appControllers = this.discoveryService.getControllers({
include: [AppModule]
});
检索模块
要检索已注册的模块,请使用 getModules() 方法:
@@filename()
getModules(): Module[];
@@switch
getModules();
此方法返回 Module[]。Module 对象包含有关模块的信息,如:
metatype- 模块类引用scope- 模块的作用域distance- 模块在模块图中的深度providers- 在此模块中注册的提供者controllers- 在此模块中注册的控制器imports- 此模块导入的模块exports- 此模块导出的提供者
例如:
@@filename()
export class ExampleProvider implements OnModuleInit {
constructor(private discoveryService: DiscoveryService) {}
onModuleInit() {
const modules = this.discoveryService.getModules();
modules.forEach(module => {
console.log(`Module: ${module.metatype.name}`);
console.log(`Providers: ${module.providers.size}`);
console.log(`Controllers: ${module.controllers.size}`);
});
}
}
@@switch
export class ExampleProvider {
constructor(discoveryService) {
this.discoveryService = discoveryService;
}
onModuleInit() {
const modules = this.discoveryService.getModules();
modules.forEach(module => {
console.log(`Module: ${module.metatype.name}`);
console.log(`Providers: ${module.providers.size}`);
console.log(`Controllers: ${module.controllers.size}`);
});
}
}
实际用例
DiscoveryService 在以下场景中特别有用:
- 动态路由注册 - 基于装饰器或元数据动态注册路由
- 插件系统 - 发现和加载插件
- 自动配置 - 基于可用的提供者自动配置服务
- 监控和调试 - 检查应用程序的结构和状态
例如,创建一个自动发现所有带有特定装饰器的服务:
@@filename()
// 自定义装饰器
export const AutoRegister = (metadata: any) => SetMetadata('auto-register', metadata);
// 发现服务
export class AutoDiscoveryService implements OnModuleInit {
constructor(private discoveryService: DiscoveryService) {}
onModuleInit() {
const providers = this.discoveryService.getProviders({
metadataKey: 'auto-register'
});
providers.forEach(wrapper => {
const metadata = Reflect.getMetadata('auto-register', wrapper.metatype);
console.log(`Auto-registering: ${wrapper.name}`, metadata);
// 执行自动注册逻辑
});
}
}
@@switch
// 自定义装饰器
export const AutoRegister = (metadata) => SetMetadata('auto-register', metadata);
// 发现服务
export class AutoDiscoveryService {
constructor(discoveryService) {
this.discoveryService = discoveryService;
}
onModuleInit() {
const providers = this.discoveryService.getProviders({
metadataKey: 'auto-register'
});
providers.forEach(wrapper => {
const metadata = Reflect.getMetadata('auto-register', wrapper.metatype);
console.log(`Auto-registering: ${wrapper.name}`, metadata);
// 执行自动注册逻辑
});
}
}
注意 DiscoveryService 只能在模块初始化后使用(即在 OnModuleInit 生命周期钩子中或之后)。在此之前,应用程序的依赖图可能尚未完全构建。