node.js - NestJS:依赖注入和提供者注册
问题描述
谁能帮我理解 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 和导入模块的情况下正确注入?
解决方案
所以让我们分解一下@Injectable()
装饰器到底发生了什么。
通常,我们使用装饰器来设置关于我们正在装饰的类、参数、方法或属性的元数据,或者我们使用它通过描述符以某种方式修改方法(如果方法装饰器)或属性(属性装饰器)。在这种情况下,@Injectable()
我们并没有真正做这些。当然我们正在设置范围元数据,但这似乎并没有设置任何关于“嘿,这个类可以通过 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 在确定注入什么时正在读取的内容。
这个元数据只有在类中的任何地方使用装饰器时才可用,并且实际上有一个关于元数据及其如何破坏它的 eslint-typescript 讨论,以及最近真正进入杂草的 PR。import type
我提出所有这些是为了说,因为你@Inject()
在构造函数中,@Injectable()
实际上是无关紧要的,除非你要设置范围级别的元数据,否则没有必要。类型元数据已经被发出,所以这就解释了为什么你不需要@Injectable()
(尽管我仍然认为拥有它是一个好主意,因为它提供了明确的意图)。
现在对于为什么注入工作正常,我保证这个不那么复杂:您将's providers InvoiceModule NotificationsService 添加NotificationsService
到了,所以它可以毫无问题地注入这里。InvoiceModule
array. This tells Nest that any service inside of
has access to
推荐阅读
- python - 使用 Python 在 Databricks 中的另一个笔记本中动态创建一个笔记本
- python - Groupby 和范围计数并在 Python 中传播
- javascript - 将 React 类组件转换为功能组件,完美渲染但功能丢失?
- c++ - 为什么我的链表是打印地址而不是打印值?
- asp.net-core - Asp.Net Core 5 auth 中间件发生在配置中指定的顺序错误
- java - Spring Boot 更改静态路径模式不自动提供 index.html
- javascript - 如何动态设置选择选项?
- angular - 更新到 Angular 11 后在 chrome 中调试问题
- html - CSS过渡属性不适用于Transform
- python - 在 python 的 fileoutput.writelines() 中使用 if else