#nestjs
#nestjs
Вопрос:
У меня есть приложение NestJS, которое использует две службы. DbService, который подключается к БД, и SlowService, который работает довольно медленно и использует внедренный DbService.
Теперь приложение должно предоставлять маршруты работоспособности за пределами базового пути api, поэтому мне нужен другой модуль, который предоставляет контроллеры для маршрутов работоспособности.
Я создал базовый модуль.
import { Module } from '@nestjs/common'
import { SlowService } from './slow.service'
import { DbService } from './db.service'
@Module({
imports: [],
controllers: [],
providers: [DbService, SlowService],
exports: [DbService, SlowService]
})
export class BaseModule {
}
ApiModule и HealthModule теперь оба импортируют базовый модуль, чтобы иметь возможность использовать службы.
imports: [BaseModule],
Есть только небольшая проблема. Кажется, что оба модуля создают свой собственный экземпляр сервиса, но мне нужно, чтобы это был один и тот же экземпляр. Я предполагаю это, потому что консоль.журнал из конструктора появляется дважды при запуске приложения. Я пропустил настройку или что-то в этом роде?
Обновить
Вот мой метод начальной загрузки, чтобы вы могли видеть, как я инициализирую модули.
async function bootstrap (): Promise<void> {
const server = express()
const api = await NestFactory.create(AppModule, server.application, { cors: true })
api.setGlobalPrefix('api/v1')
await api.init()
const options = new DocumentBuilder()
.setTitle('...')
.setLicense('MIT', 'https://opensource.org/licenses/MIT')
.build()
const document = SwaggerModule.createDocument(api, options)
server.use('/swaggerui', SwaggerUI.serve, SwaggerUI.setup(document))
server.use('/swagger', (req: express.Request, res: express.Response, next?: express.NextFunction) => res.send(document))
const health = await NestFactory.create(HealthModule, server.application, { cors: true })
health.setGlobalPrefix('health')
await health.init()
http.createServer(server).listen(Number.parseInt(process.env.PORT || '8080', 10))
}
const p = bootstrap()
Комментарии:
1. Это удивительно для меня. Оба контроллера используют область внедрения по умолчанию при внедрении
SlowService
?2. Да, они это делают. Я попытался отладить его, и, похоже, они даже используют один и тот же контекст. Все еще консоль. журнал из конструктора отображается дважды. И поверьте мне, я был очень удивлен, так как новый контроллер работоспособности lightwight испортил производительность моей тестовой системы.
Ответ №1:
Возможно, вы определили сервисы как поставщиков для 2 модулей. Что вам нужно сделать, это определить ваш BaseModule
как импорт только в том модуле, где он вам нужен.
Этот пример демонстрирует службу, OtherService
в OtherModule
которой требуется DbService
from BaseModule
. Если вы запустите пример, вы увидите, что он создает экземпляр только DbService
один раз.
import {Injectable, Module} from '@nestjs/common';
import {NestFactory} from '@nestjs/core';
@Injectable()
export class SlowService {
constructor() {
console.log(`Created SlowService`);
}
}
@Injectable()
export class DbService {
constructor() {
console.log(`Created DbService`);
}
}
@Module({
imports: [],
providers: [SlowService, DbService],
exports: [SlowService, DbService]
})
export class BaseModule {}
@Injectable()
export class OtherService {
constructor(private service: DbService) {
console.log(`Created OtherService with dependency DbService`);
}
}
@Module({
imports: [BaseModule],
providers: [OtherService],
})
export class OtherModule {}
@Module({
imports: [
BaseModule,
OtherModule
],
})
export class AppModule {}
NestFactory.createApplicationContext(AppModule).then((app) => console.log('🥑 context created'));
Эта суть демонстрирует ПЛОХОЕ использование провайдеров, что приводит к DbService
двойному созданию экземпляра: https://gist.github.com/martijnvdbrug/12faf0fe0e1fc512c2a73fba9f31ca53
Комментарии:
1. Большое вам спасибо за ваш подробный ответ. Это именно то, что я думал, что сделал, но я изучу это снова.
2. @Woozar, у меня такая же проблема, и этот ответ мне тоже помог. Я предлагаю выбрать его как принятый.
3. Это ценная информация, которую нелегко извлечь из документации. Большое вам спасибо за такой уровень детализации; для некоторых, таких как я, тонкость очень трудна для понимания.
4. Если вы импортируете
BaseService
на нескольких модулях, то службы внутри него будут установлены несколько раз. Действительно, каждый модуль имеет одинаковые сервисы, но это не совсем верно для модуля, имеющего один и тот же экземпляр сервисов с другими модулями.5. @Khatri, если поставщик не экспортирован, он будет доступен только для участников (и дочерних элементов) модуля. Думайте об этом как о «частной» службе, при экспорте она затем станет доступной для других модулей, импортирующих эту. Надеюсь, это имеет смысл
Ответ №2:
Я просто оставляю это здесь на случай, если кому-то еще это понадобится.
Если вы действительно хотите, чтобы все модули в вашем приложении использовали один и тот же экземпляр, то, вероятно, вам нужно использовать глобальную переменную и поместить в нее свои сервисы.
Сначала определите свой сервис в корне вашего исходного приложения, которое app.module
.
nest g s shared-services/db
Во-вторых, укажите свой сервис в глобальной переменной. (Сосредоточьтесь на прокомментированном коде)
import { Injectable } from '@nestjs/common';
/* Define global variable as "any" so we don't get nasty error. */
declare var global: any;
@Injectable()
export class DbService {
constructor() {
console.log(`Created DbService`);
/* Put the class inside global variable. */
global.dbService = this;
}
}
Наконец, вы можете вызвать свою службу с другого контроллера или служб.
import { Injectable } from '@nestjs/common';
import { DbService} from './../shared-services/db.service';
/* Define global variable as "any" so we don't get nasty error. */
declare var global: any;
@Injectable()
export class OtherService {
/* Call the service. */
protected readonly dbService: DbService = global.dbService;
constructor() {
}
}
И все готово.
Я действительно надеюсь, что в будущем NestJS будет иметь те же встроенные функции, что и Angular, поэтому нам действительно не нужно беспокоиться об экспорте-импорте каких-либо сервисов.
Комментарии:
1. Разве это не антишаблон? Зачем использовать этот подход по сравнению с импортом / предоставлением этого в корневом модуле и / или @Global module? Не будет ли это также означать, что он нигде не вводится, что противоречит цели @Injectable? Если это тот подход, который вам нужен, кажется разумным просто вставить его в файл экспорта, который импортируется туда, где вам это нужно.
2. Это не очень хороший подход
3. Зачем тогда вообще использовать Nest, если вы хотите сохранить его снаружи…