#node.js #dependency-injection #service #nestjs
#node.js #внедрение зависимостей #Обслуживание #nestjs
Вопрос:
Кто-нибудь может помочь мне понять основы DI Nest, мой вопрос:
«Возможно ли иметь класс обслуживания без @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) {
....
}
}
А затем он был зарегистрирован в другом модуле в массиве поставщиков:
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()
с мы на самом деле не делаем ни того, ни другого. Конечно, мы устанавливаем метаданные области видимости, но, похоже, на самом деле это не устанавливает никаких метаданных о «Эй, этот класс можно вводить через Nest framework». Это потому, что @Injectable()
то, что на самом деле настраивает нас, — это специальное свойство компилятора tsconfig
and tsc
, emitDecoratorMetadata
свойство. С помощью этого свойства typescript добавит множество дополнительных функций в начале и в конце файла. В целом эти функции выглядят следующим образом
var __decorate = (this amp;amp; 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" amp;amp; 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 amp;amp; r amp;amp; Object.defineProperty(target, key, r), r;
};
var __metadata = (this amp;amp; this.__metadata) || function (k, v) {
if (typeof Reflect === "object" amp;amp; 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 о метаданных и о том, как import type
их нарушать, а также недавний PR, который действительно попадает в сорняки вещей.
Я привожу все это, чтобы сказать, что, поскольку у вас есть @Inject()
конструктор, он на самом @Injectable()
деле является посторонним и не является необходимым, если только вы не собираетесь устанавливать метаданные уровня области. Метаданные типа уже будут отправлены, так что это объясняет, почему вам не нужно @Injectable()
(хотя я все еще думаю, что это хорошая идея, потому что она обеспечивает четкое намерение).
Теперь о том, почему внедрение работает должным образом, я обещаю, что это менее сложно: вы добавили NotificationsService
в InvoiceModule
«
NotificationsService InvoiceModule NotificationsService для поставщиков array. This tells Nest that any service inside of
has access to
«, чтобы его можно было без проблем ввести здесь.
Комментарии:
1. Спасибо за ваше объяснение, поэтому я делаю вывод, что класс, подобный NotificationService, может существовать без принадлежности к какому-либо модулю, который его экспортирует, и, во-вторых, используя register provider , как в этом случае, Nest за кулисами создает новый экземпляр NotificationService, нет необходимости использовать значение: new NotificationService