【NestJS系列】核心概念:Providers提供者

前言

ProvidersNest中的一個基本概念,許多Nest中定義的類都可以被視爲一個Provider,比如:service、repository、factory、helper等,它們都可以通過constructor注入依賴關係,這就意味着類與類之間可以創建各種依賴關係,並且維護各個類之間依賴關係的工作將委託給Nest運行時系統。

Provider類(service)基本用法

前面幾章我們通過nest-cli生成的代碼中就包含有service

比如:

// nanjiu.service.ts
import { Injectable } from '@nestjs/common';
import { CreateNanjiuDto } from './dto/create-nanjiu.dto';
import { UpdateNanjiuDto } from './dto/update-nanjiu.dto';

@Injectable()
export class NanjiuService {
  create(createNanjiuDto: CreateNanjiuDto) {
    return 'This action is nanjiu post';
  }

  findAll() {
    return `This action returns all nanjiu`;
  }

  findOne(id: number) {
    return `This action returns a #${id} nanjiu`;
  }

  update(id: number, updateNanjiuDto: UpdateNanjiuDto) {
    return `This action updates a #${id} nanjiu`;
  }

  remove(id: number) {
    return `This action removes a #${id} nanjiu`;
  }
}

使用步驟如下:

@Injectable()裝飾器

這裏的NanjiuService類通過@Injectable裝飾器標記爲一個provider,表明該類可以被NestIOC容器管理

在module中註冊

服務需要在對應的module中進行註冊,如果不註冊IOC容器是不會幫你創建對象的,而且還會報錯

// nanjiu.module.ts
@Module({
  controllers: [NanjiuController],
  providers: [NanjiuService]
})
export class NanjiuModule {}

在controller中注入並使用

module中註冊service類後,再通過controller的構造函數進行注入,那麼該類就可以在controller中去使用了

// nanjiu.controller.ts

@Controller('nanjiu')
export class NanjiuController {
  constructor(private readonly nanjiuService: NanjiuService) {}

  @Post()
  @Header('Cache-Control', 'none')
  create(@Body() createNanjiuDto: CreateNanjiuDto) {
    console.log('body', createNanjiuDto)
    return this.nanjiuService.create(createNanjiuDto);
  }
}

可以看到是通過類構造函數 constructor(private readonly nanjiuService: NanjiuService) {}這種方式來進行依賴注入的,Nest提供了IOC容器利用Typescript自帶類型的特點自動創建對象的能力,注意這裏是單例模式,如果該Service在其它地方也被用過,那麼會在不會重新創建對象,各個應用只會有一個該Service的對象,容器會先尋找當前有沒有,如果沒有再進行創建。

自定義Provider

Provider可以是一個值(value),也可以是一個類(class),還可以是一個工廠函數(factory)

useClass

上面providers的那種寫法其實是一種簡寫,它的完整寫法應該是這樣:

// nanjiu.module.ts
@Module({
  controllers: [NanjiuController], // 控制器
  providers: [{
    provide: 'NANJIU',  // 自定義依賴注入的標識
    useClass: NanjiuService // 依賴注入的類
  }]
})
export class NanjiuModule {}

完整寫法可以通過provide屬性給不同的provider標註不同的token

然後再controller中需要使用@Inject(對應的token)進行注入

// nanjiu.controller.ts
@Controller('nanjiu')
export class NanjiuController {
  constructor(@Inject('NANJIU') private readonly nanjiuService: NanjiuService) {}

  @Post()
  @Header('Cache-Control', 'none')
  create(@Body() createNanjiuDto: CreateNanjiuDto) {
    console.log('body', createNanjiuDto, this.nanjiuService)
    return true
    return this.nanjiuService.create(createNanjiuDto);
  }
}

useValue

還可以使用useValue自定義注入值

// nanjiu.module.ts
@Module({ // 模塊裝飾器
  controllers: [NanjiuController], // 控制器
  providers: [{
    provide: 'NANJIU',  // 自定義依賴注入的標識
    useValue: {
      name: 'nanjiu' // 依賴注入的值
    }
  }]
})

4-1.png

useFactory

工廠函數可以提供動態的provider,由factory函數的返回值來確定,factory函數可以很簡單也可以很複雜,它也可以使用其它provider,不過需要在inject屬性進行注入,注入的provider可以是可選的

  • 工廠函數可以接受(可選)參數。

  • (可選)inject屬性接受一組提供程序,Nest 將在實例化過程中解析這些提供程序並將其作爲參數傳遞給工廠函數。這兩個列表應該是相關的:Nest 將以inject相同的順序將列表中的實例作爲參數傳遞給工廠函數。

// nanjiu.module.ts
import { Module } from '@nestjs/common';
import { NanjiuService } from './nanjiu.service';
import { UserService } from 'src/user/user.service';
import { NanjiuController } from './nanjiu.controller';

@Module({ // 模塊裝飾器
  controllers: [NanjiuController], // 控制器
  providers: [{
    provide: 'NANJIU',  // 自定義依賴注入的標識
    useClass: NanjiuService // 依賴注入的類
  },
  UserService,
  {
    provide: 'USER', // 自定義依賴注入的標識
    useFactory: (...args) => { // 工廠模式
      console.log('useFactory', args)
      return new UserService() // 依賴注入的類
    },
    inject: [UserService] // 依賴注入的類
  }

]
})
export class NanjiuModule {}

4-2.png

可選的Provider

有時你可能存在不一定需要解決的依賴關係。例如,你的類可能依賴於配置對象,但如果沒有傳遞任何內容,則應使用默認值。在這種情況下,依賴關係變得可選,這時候可以給對應的注入服務再增加一個@Optional()裝飾器就行

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

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

異步Provider

useFactory可以返回一個promise 或者其他異步操作,Nest 將在實例化任何依賴(注入)此類提供程序的類之前等待promise的結果。

// nanjiu.module.ts
@Module({ // 模塊裝飾器
  controllers: [NanjiuController], // 控制器
  providers: [
  UserService,
  {
    provide: 'USER', // 自定義依賴注入的標識
    useFactory: async () => { // 工廠模式
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(new UserService())
        }, 1000)
      })
    },
    inject: [UserService] // 依賴注入的類
  }

]
})
export class NanjiuModule {}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章