[英]In nest.js, is it possible to get service instance inside a param decorator?
[英]In Nest.js, how to get a service instance inside a decorator?
在CustomDecorator
,如何访问 Nest.js 中定义的服务实例?
export const CustomDecorator = (): MethodDecorator => {
return (
target: Object,
propertyKey: string | symbol,
descriptor: PropertyDescriptor
) => {
// Here, is possibile to access a Nest.js service (i.e. TestService) instance?
return descriptor;
}
};
聚会迟到了,但由于我遇到了类似的问题( 在装饰器中使用全局嵌套模块)并偶然发现了这个问题。
import { Inject } from '@nestjs/common';
export function yourDecorator() {
const injectYourService = Inject(YourServiceClass);
return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
// this is equivalent to have a constructor like constructor(yourservice: YourServiceClass)
// note that this will injected to the instance, while your decorator runs for the class constructor
injectYourService(target, 'yourservice');
// do something in you decorator
// we use a ref here so we can type it
const yourservice: YourServiceClass = this.yourservice;
yourservice.someMethod(someParam);
};
}
我们有几点:
decorated instance
之前执行的属性装饰器。decorated instance
的注入器解析的some instance
decorated instance
。 作为一种直接的方法 - 使用decorated instance
注入的some instance
decorated instance
。
@Injectable()
export class CatsService {
constructor(public myService: MyService){}
@CustomDecorator()
foo(){}
}
export const CustomDecorator = (): MethodDecorator => {
return (
target: Object,
propertyKey: string | symbol,
descriptor: PropertyDescriptor
) => {
const originalMethod = descriptor.value;
descriptor.value = function () {
const serviceInstance = this;
console.log(serviceInstance.myService);
}
return descriptor;
}
};
PS 我认为以某种方式可以使用 Injector 的实例来获得任何所需的实例(如angular 那样)。
遇到这个问题并花了一天时间试图找出一个好的答案。 这可能不适合所有用例,但我能够复制 Nest 核心包中的通用模式以满足我的需求。
我想创建我自己的装饰器来注释控制器方法来处理事件(例如, @Subscribe('some.topic.key') async handler() { ... })
)。
为了实现这一点,我的装饰用SetMetadata
从@nestjs/common
注册我所需的一些元数据(它被应用到方法名,它属于类,该方法的引用)。
export const Subscribe = (topic: string) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
SetMetadata<string, RabbitSubscriberMetadataConfiguration>(
RABBITMQ_SUBSCRIBER,
{
topic,
target: target.constructor.name,
methodName: propertyKey,
callback: descriptor.value,
},
)(target, propertyKey, descriptor);
};
};
从那里,我能够创建自己的模块,该模块连接到 Nest 的生命周期钩子,以查找我用我的装饰器装饰的所有方法,并对其应用一些逻辑,例如:
@Module({
imports: [RabbitmqChannelProvider],
providers: [RabbitmqService, MetadataScanner, RabbitmqSubscriberExplorer],
exports: [RabbitmqService],
})
export class RabbitmqModule implements OnModuleInit {
constructor(
private readonly explorer: RabbitmqSubscriberExplorer,
private readonly rabbitmqService: RabbitmqService,
) {}
async onModuleInit() {
// find everything marked with @Subscribe
const subscribers = this.explorer.explore();
// set up subscriptions
for (const subscriber of subscribers) {
await this.rabbitmqService.subscribe(
subscriber.topic,
subscriber.callback,
);
}
}
}
资源管理器服务使用@nestjs/core
一些实用程序来内省容器并处理查找所有带有元数据的装饰函数。
@Injectable()
export class RabbitmqSubscriberExplorer {
constructor(
private readonly modulesContainer: ModulesContainer,
private readonly metadataScanner: MetadataScanner,
) {}
public explore(): RabbitSubscriberMetadataConfiguration[] {
// find all the controllers
const modules = [...this.modulesContainer.values()];
const controllersMap = modules
.filter(({ controllers }) => controllers.size > 0)
.map(({ controllers }) => controllers);
// munge the instance wrappers into a nice format
const instanceWrappers: InstanceWrapper<Controller>[] = [];
controllersMap.forEach(map => {
const mapKeys = [...map.keys()];
instanceWrappers.push(
...mapKeys.map(key => {
return map.get(key);
}),
);
});
// find the handlers marked with @Subscribe
return instanceWrappers
.map(({ instance }) => {
const instancePrototype = Object.getPrototypeOf(instance);
return this.metadataScanner.scanFromPrototype(
instance,
instancePrototype,
method =>
this.exploreMethodMetadata(instance, instancePrototype, method),
);
})
.reduce((prev, curr) => {
return prev.concat(curr);
});
}
public exploreMethodMetadata(
instance: object,
instancePrototype: Controller,
methodKey: string,
): RabbitSubscriberMetadataConfiguration | null {
const targetCallback = instancePrototype[methodKey];
const handler = Reflect.getMetadata(RABBITMQ_SUBSCRIBER, targetCallback);
if (handler == null) {
return null;
}
return handler;
}
}
我并不认为这是处理这个问题的最佳方式,但它对我来说效果很好。 使用此代码风险自负,它应该可以帮助您入门:-)。 我修改了此处提供的代码: https : //github.com/nestjs/nest/blob/5.1.0-stable/packages/microservices/listener-metadata-explorer.ts
我试图在 ParamDecorator 中使用我的配置服务,所以我通过创建它的新实例来访问我的服务:
export const MyParamDecorator = createParamDecorator((data, req) => {
// ...
const configService = new ConfigService(`${process.env.NODE_ENV || 'default'}.env`);
const myConfigValue = configService.getMyValue();
// ...
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.