provider
是Nest的基本概念。許多基本的Nest類均可以被視爲 provider
– services
, repositories
, factories
, helpers
,等。提供程序的主要思想是它能夠注入依賴項。這意味着對象能夠彼此建立各類關係,而且「鏈接」對象實例的功能在很大程度上能夠委託給Nest運行時系統。Providers只是帶有@Injectable()
裝飾器的類typescript
在上一章中,咱們構建了一個簡單的CatsController
。控制器應處理HTTP請求,並將更復雜的任務委託給Providers。Providers只是普通的JavaScript類,在@Injectable()
其類聲明以前帶有裝飾器json
因爲Nest容許以更面向對象的方式設計和組織依賴項,咱們強烈建議遵循SOLID的原則。設計模式
提示: 設計模式中的SOLID原則,分別是單一原則、開閉原則、里氏替換原則、接口隔離原則、依賴倒置原則。前輩們總結出來的,遵循五大原則可使程序解決緊耦合,更加健壯。
讓咱們從建立一個簡單的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) {}
提供程序一般具備與應用程序生命週期同步的生命週期(「做用域」)。 引導應用程序時,必須解決每一個依賴關係,所以必須實例化每一個提供程序。 一樣,當應用程序關閉時,每一個提供程序都將被銷燬。 可是,也有一些方法可使提供程序的生命週期達到請求範圍。 您能夠在此處閱讀有關這些技術的更多信息。
Nest內置了IOC容器( IOC: 控制反轉 )可解決提供程序之間的關係。IOC底層的依賴注入功能,但其實遠比咱們到目前爲止所描述更增強大。
@Injectable()裝飾器只是冰山一角,並非定義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,則應始終使用基於構造函數的注入。
如今咱們已經定義了提供程序(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 } }