4. Nest.js Providers

文章介绍了NestJS框架中的提供者概念,包括服务、存储库等,强调了依赖注入的重要性。通过创建CatsService和CatsController的例子,阐述了如何使用@Injectable()装饰器声明服务,并在控制器中通过构造函数注入依赖。文章还提到了提供者的生命周期、自定义提供者、可选提供者以及基于属性的注入等高级话题。
摘要由CSDN通过智能技术生成

Providers是Nest中的一个基本概念。许多基本的Nest类可以被视为提供者——服务、存储库、工厂、助手等等。提供者的主要思想是它可以作为依赖注入;这意味着对象可以创建彼此之间的各种关系,并且“连接”对象实例的功能可以在很大程度上委托给Nest运行时系统。

image.png

在前一章中,我们构建了一个简单的CatsController。控制器应该处理HTTP请求,并将更复杂的任务委托给提供商。提供程序是在模块中声明为提供程序的普通JavaScript类。

[!hint]
由于Nest允许以更面向对象的方式设计和组织依赖项,因此我们强烈建议遵循SOLID原则([[SOLID]])。

服务

让我们从创建一个简单的CatsService开始。该服务将负责数据存储和检索,并被设计为由CatsController使用,因此将其定义为提供者是一个很好的候选者。

import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}

[!hint]
要使用CLI创建服务,只需执行$ nest g service cats命令。

我们的CatsService是一个具有一个属性和两个方法的基本类。唯一的新特性是它使用了@Injectable()装饰器。@Injectable()装饰器附加了元数据,它声明CatsService是一个可以由Nest IoC容器管理的类。顺便说一下,这个例子也使用了一个Cat接口,它看起来可能是这样的:

export interface Cat {
  name: string;
  age: number;
  breed: string;
}

现在我们有了一个检索猫的服务类,让我们在CatsController中使用它:

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

CatsService是通过类构造函数注入的。注意这里使用了私有语法。这种简写允许我们在同一位置立即声明和初始化catsService成员。

依赖注入

Nest是围绕通常称为依赖注入的强大设计模式构建的。我们建议在Angular官方文档中阅读一篇关于这个概念的好文章([[理解依赖注入]])。

在Nest中,由于TypeScript的功能,管理依赖非常容易,因为它们只按类型解析。在下面的示例中,Nest将通过创建和返回catsService的实例来解析catsService(或者,在单例的正常情况下,如果已经在其他地方请求了它,则返回现有的实例)。这个依赖被解析并传递给你的控制器的构造函数(或分配给指定的属性):

constructor(private catsService: CatsService) {}

作用域

Providers通常有一个与应用程序生命周期同步的生命周期(“作用域”)。当应用程序被引导时,必须解析每个依赖项,因此必须实例化每个提供者。类似地,当应用程序关闭时,每个提供程序都将被销毁。然而,也有一些方法可以使您的提供者生命周期限定在request-scoped内。你可以在这里阅读更多关于这些技术的内容。

自定义 Providers

Nest有一个内置的控制反转(IoC)容器来解析providers之间的关系。这个特性是上述依赖注入特性的基础,但实际上比我们目前所描述的要强大得多。有几种方法可以定义提供程序:您可以使用普通值、类以及异步或同步工厂。这里提供了更多示例

Optional providers

偶尔,您可能会有不需要解析的依赖项。例如,您的类可能依赖于配置对象,但如果没有传递,则应使用默认值。在这种情况下,依赖项成为可选的,因为缺少配置提供程序不会导致错误。

要指出一个提供程序是可选的,可以在构造函数的签名中使用@Optional()装饰器。

import { Injectable, Optional, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {}
}

请注意,在上面的示例中,我们使用的是自定义provider,这就是我们包含HTTP_OPTIONS自定义令牌的原因。前面的例子展示了基于构造函数的注入,通过构造函数中的类 表示 依赖项。在这里阅读有关自定义提供程序及其相关令牌的更多信息。

基于属性的注入

到目前为止,我们使用的技术被称为基于构造函数的注入,因为提供程序是通过构造函数方法注入的。在一些非常特殊的情况下,基于属性的注入可能很有用。例如,如果您的顶级类依赖于一个或多个提供程序,那么通过从构造函数调用子类中的super()来传递它们可能非常繁琐。为了避免这种情况,你可以在属性级别使用@Inject()装饰器。

import { Injectable, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  @Inject('HTTP_OPTIONS')
  private readonly httpClient: T;
}

[!warning]
如果你的类没有扩展其他providers,你应该总是使用基于构造函数的注入。

Provider registration

现在我们已经定义了一个provider(CatsService),并且有了该服务的消费者(CatsController),我们需要向Nest注册该服务,以便它可以执行注入。我们通过编辑模块文件(app.module.ts)并将服务添加到@Module()装饰器的providers数组中来实现这一点。

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class AppModule {}

Nest现在可以解析CatsController类的依赖关系了。

现在我们的目录结构应该是这样的:

image.png

手动实例化

到目前为止,我们已经讨论了Nest如何自动处理解析依赖项的大部分细节。在某些情况下,你可能需要走出内置的依赖注入系统,手动检索或实例化提供商。下面我们将简要讨论两个这样的主题。

  • 要获取现有实例或动态实例化提供程序,可以使用 Module reference.
  • 要在bootstrap()函数中获取提供商(例如,对于没有控制器的独立应用程序,或在引导期间使用配置服务),请参阅独立应用程序
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值