NestJS:依赖检查和提供程序注册 [英] NestJS: Dependency Inyection and Provider Registration

查看:78
本文介绍了NestJS:依赖检查和提供程序注册的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以帮助我了解DI Nest基本原理吗?

Can anyone help me to understand DI Nest Fundamentals, my question:

是否可能具有没有@Injectable注释的服务类 ,并且该类不属于任何模块?"我在互联网上看到了如下示例:

"Is it possible to have a service class without @Injectable annotattion, and also this class does not belong to any module?" I saw on internet an example like below:

此类位于一个公共文件夹中:

This class exists in a common folder:

export class NotificationService {
  constructor(
    @Inject(Logger) private readonly logger: LoggerService,
    private readonly appConfigService: AppConfigService,
    @Inject(HttpService) private readonly httpService: HttpService
  ) {}
 
  async sendNotification(msg: string) {
   ....
  } 
}

然后将其注册在providers数组的另一个模块中:

And then it was registered in another module in the the providers array:

import { Module, Logger, forwardRef, HttpModule } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { NotificationService } from '../../commons/notification/notification.service';
 
@Module({
    imports: [
        ...
    ],
    controllers: [InvoiceController],
    providers: [
        InvoiceService,
        NotificationService,
        Logger],
    exports: [InvoiceService]
})
export class InvoiceModule { }

然后将其注入其他服务的构造方法中

Then it was injected in other service's constructor method

@Injectable()
export class InvoiceService {
 
    constructor(
        @Inject(Logger) private readonly logger: LoggerService,
        private readonly notificationService: NotificationService) { }
 
...
}

这很好,但是我不知道为什么.为什么在没有添加@Injectable,没有和导入模块的情况下正确注入了通知服务?

This works fine, but I don't know why. Why the notification service was injected correctly without add @Injectable, and without and import module?

推荐答案

因此,让我们分解一下 @Injectable()装饰器的实际情况.

So let's break down what's really happening with the @Injectable() decorator.

通常,我们使用装饰器来设置有关我们正在装饰的类,参数,方法或属性的元数据,或者我们正在使用它来通过描述符以某种方式修改方法(如果是方法装饰器)或属性(属性装饰器).在 @Injectable()的情况下,我们实际上并没有做任何一个.确保我们设置作用域元数据,但这似乎并没有设置任何有关嘿,此类可通过Nest框架进行注入"的元数据.这是因为 @Injectable()确实设置的,是 tsconfig tsc 的特殊属性编译器的 emitDecoratorMetadata 属性.有了这个属性,打字稿将在文件的开头和结尾添加一堆额外的功能.这些功能通常看起来像这样

Normally, we use decorators for setting metadata about the class, parameter, method, or property that we are decorating, or we are using it to somehow modify the method (if method decorator) or the property (property decorator) via descriptors. In the case of @Injectable() we aren't really doing either of these. Sure we're setting the scope metadata, but this doesn't really seem to set any metadata about "Hey, this class is injectable via the Nest framework". That's because what @Injectable() is really setting us up for is a special property of the tsconfig and tsc compiler, the emitDecoratorMetadata property. With this property, typescript will add on a bunch of extra functions at the beginning and end of the file. These functions look generally like this

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};

DelegatorService = __decorate([
    common_1.Injectable(),
    __metadata("design:paramtypes", [http_interceptor_service_1.HttpInterceptorService,
        websocket_interceptor_service_1.WebsocketInterceptorService,
        rpc_interceptor_service_1.RpcInterceptorService,
        gql_interceptor_service_1.GqlInterceptorService])
], DelegatorService);

这是非常重要的部分,因为实际上,此" design:paramtypes" 是Nest在确定要注入的内容时正在读取的内容.

This is the super important part, because this "design:paramtypes" is actually what Nest is reading when it comes determining what to inject.

仅当在类中的任何地方使用装饰器并且存在实际上是关于元数据以及 import type 如何将其破坏的eslint型脚本讨论,以及

This metadata is only available when a decorator is used anywhere in the class, and there was actually an eslint-typescript discussion about the metadata and how import type breaks it, along with a recent PR that really gets into the weeds of things.

我要说的全部是因为您在构造函数中有 @Inject(),所以 @Injectable()实际上是多余的,除非没有必要,否则您将要设置作用域级别的元数据.metadat类型将被发出,因此可以解释为什么您不需要 @Injectable()(尽管我仍然认为将其提供清晰的意图是一个好主意).

I bring all of this up to say that because you have @Inject() in the constructor, the @Injectable() is actually extraneous, and not necessary unless you're going to be setting scope level metadata. The type metadat will alrady be emitted, so that explains why you don't need @Injectable() (though I still think it's a good idea to have it cause it provides clear intent).

现在说明为什么注入可以正常工作,我保证这一过程不太复杂:您在 InvoiceModule 提供者中添加了 NotificationsService 数组.这告诉Nest, InvoiceModule 内部的任何服务都可以访问 NotificationsService`,因此可以毫无问题地将其插入此处.

Now for why the injection works properly, I promise this one is less complex: you added the NotificationsService to the InvoiceModule's providersarray. This tells Nest that any service inside ofInvoiceModulehas access toNotificationsService` so it can be injected here without a problem.

这篇关于NestJS:依赖检查和提供程序注册的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆