NestJS:依赖注入和提供者注册
Posted
技术标签:
【中文标题】NestJS:依赖注入和提供者注册【英文标题】:NestJS: Dependency Injection and Provider Registration 【发布时间】:2021-04-23 00:24:26 【问题描述】:谁能帮我理解 DI Nest Fundamentals,我的问题:
“是否有可能有一个服务类没有@Injectable 注释,而且这个类不属于任何模块?”我在网上看到一个例子如下:
这个类存在于一个公共文件夹中:
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 数组的另一个模块中注册:
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
然后注入到其他服务的构造方法中
@Injectable()
export class InvoiceService
constructor(
@Inject(Logger) private readonly logger: LoggerService,
private readonly notificationService: NotificationService)
...
这很好用,但我不知道为什么。为什么通知服务在没有添加@Injectable和没有导入模块的情况下正确注入?
【问题讨论】:
【参考方案1】:那么让我们来分析一下@Injectable()
装饰器到底发生了什么。
通常,我们使用装饰器来设置关于我们正在装饰的类、参数、方法或属性的元数据,或者我们使用它通过描述符以某种方式修改方法(如果方法装饰器)或属性(属性装饰器) .在@Injectable()
的情况下,我们并没有真正做这些。当然我们是setting the scope metadata,但这似乎并没有真正设置任何关于“嘿,这个类可以通过 Nest 框架注入”的元数据。那是因为@Injectable()
是真正 设置我们的是tsconfig
和tsc
编译器的特殊属性,emitDecoratorMetadata
属性。有了这个属性,typescript 会在文件的开头和结尾添加一堆额外的函数。这些函数一般看起来是这样的
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 在确定注入什么时正在读取的内容。
这个元数据只有在类中的任何地方使用装饰器时才可用,was actually an eslint-typescript discussion 关于元数据以及import type
如何破坏它,以及真正深入杂草的a recent PR。
我提出所有这些是为了说因为您在构造函数中有@Inject()
,所以@Injectable()
实际上是无关紧要的,除非您要设置范围级别的元数据,否则没有必要。类型元数据已经被发出,这就解释了为什么你不需要@Injectable()
(尽管我仍然认为拥有它是个好主意,因为它提供了明确的意图)。
现在为什么注入工作正常,我保证这个不那么复杂:您将 NotificationsService
添加到 InvoiceModule
's
providersarray. This tells Nest that any service inside of
InvoiceModulehas access to
NotificationsService` 以便可以注入在这里没有问题。
【讨论】:
感谢您的解释,所以我推断像 NotificationService 这样的类可以存在而不属于任何导出它的模块,其次,在这种情况下使用 register provider , Nest在后台新建一个NotificationService实例,不需要useValue:new NotificationService以上是关于NestJS:依赖注入和提供者注册的主要内容,如果未能解决你的问题,请参考以下文章
nestjs 单元测试 createTestingModule 依赖注入
使用 Prisma 2 和 NestJS 进行日志记录 - 依赖注入问题?