Nestjs 自翻中文文档(三)

Nestjs中文文档(三): 提供者Providers

provider是Nest的基本概念。许多基本的Nest类均可以被视为 providerservices, repositories, factories, helpers,等。提供程序的主要思想是它能够注入依赖项。这意味着对象能够彼此建立各类关系,而且“链接”对象实例的功能在很大程度上能够委托给Nest运行时系统。Providers只是带有@Injectable()装饰器的类typescript

image

在上一章中,咱们构建了一个简单的CatsController。控制器应处理HTTP请求,并将更复杂的任务委托给Providers。Providers只是普通的JavaScript类,在@Injectable()其类声明以前带有装饰器json

因为Nest容许以更面向对象的方式设计和组织依赖项,咱们强烈建议遵循SOLID的原则。设计模式

提示: 设计模式中的SOLID原则,分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则。前辈们总结出来的,遵循五大原则可使程序解决紧耦合,更加健壮。

服务 service

让咱们从建立一个简单的CatsService开始.数组

这项服务将负责数据存储和检索( 简而言之:服务负责数据的存入和查询 ),而且是为catscocontroller设计的,所以它很适合被定义为提供者Providersapp

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;
  }
}
提示: 建立一个服务只须要 nest g service cats

咱们的CatsService是一个具备一个属性和两个方法的基本类。惟一的新特性是它使用@Injectable()装饰器。@Injectable()附加元数据,它告诉Nest这个类是一个Nest Providers。顺便说一下,这个例子还使用了一个Cat接口,它可能看起来像这样:异步

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

如今咱们有了一个服务类来检索cats,让咱们在CatsController中使用它async

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 readonly catsService: CatsService) {}

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

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

CatsService经过类构造函数注入。注意私有只读语法的使用。这个参数容许咱们在同一个位置当即声明和初始化catsService成员ide

依赖注入

Nest创建在强大的设计模式(一般称为“ 依赖注入”)周围。咱们建议在Angular官方文档中阅读有关此概念的精彩文章。毕竟Nest但是直接借鉴了Angular。函数

在Nest中,因为具备TypeScript功能,管理依赖关系很是容易,由于它们仅按类型进行解析。在下面的示例中,Nest将catsService经过建立并返回的实例CatsService(或者在单例的正常状况下,若是已在其余地方请求了现有的实例,则返回现有实例)来解决。此依赖关系已解决,并传递给控制器​​的构造函数(或分配给指定的属性):this

constructor(private readonly catsService: CatsService) {}

做用域

提供程序一般具备与应用程序生命周期同步的生命周期(“做用域”)。 引导应用程序时,必须解决每一个依赖关系,所以必须实例化每一个提供程序。 一样,当应用程序关闭时,每一个提供程序都将被销毁。 可是,也有一些方法可使提供程序的生命周期达到请求范围。 您能够在此处阅读有关这些技术的更多信息。

自定义Providers

Nest内置了IOC容器( IOC: 控制反转 )可解决提供程序之间的关系。IOC底层的依赖注入功能,但其实远比咱们到目前为止所描述更增强大。

@Injectable()装饰器只是冰山一角,并非定义Providers的惟一方法。 实际上,您可使用纯文本值,类以及异步或同步工厂。 这里提供更多示例

可选Providers

有时,您可能具备不必定必须解决的依赖关系。 例如,您的类可能依赖于配置对象,可是若是未传递任何配置对象,则应使用默认值。 在这种状况下,依赖项变为可选的,由于缺乏配置提供程序不会致使错误。

要指示Providers是可选的,请在构造函数的签名中使用@Optional()装饰器。

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

基于属性的注入

到目前为止,咱们已使用的技术称为基于构造函数的注入,由于Providers是经过构造方法注入的。

在某些很是特定的状况下,基于属性的注入可能会有用。 例如,若是您的顶级类依赖于一个或多个Providers,那么经过从构造函数中调用子类中的super()来将它们一直传递下去可能会很是繁琐。 为了不这种状况,能够在属性级别使用@Inject()装饰器。

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

@Injectable()
export class HttpService<T> {
  @Inject('HTTP_OPTIONS')
  private readonly httpClient: T;
}
若是您的类没有扩展其余的Providers,则应始终使用基于构造函数的注入。

Providers的注册

如今咱们已经定义了提供程序(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该类的依赖关系。

这是咱们的目录结构如今的外观:( 使用类JSON的方式代表,但愿能看懂 )

{
    src: {
        cats: {
          dto: {
            create-cat.dto.ts
          },
          interfaces: {
            cat.interface.ts
          },
          cats.service.ts,
          cats.controller.ts
        },
        app.module.ts,
        main.ts
    }
}
相关文章
相关标签/搜索