(四)Provider

84 阅读2分钟

依賴注入 (Dependency Injection)

image.png

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
//
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    AppService
  ],
})
export class AppModule {}

//
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    { provide: AppService, useClass: AppService }
  ],
})
export class AppModule {}

Provider

image.png

  1. @Injectable 讓 Nest 知道這個 class 是可以由控制反轉容器管理的
這裡以 app.service.ts 為例:

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

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}
在 Module 中,只需要於 providers 中聲明該 Service 即可。這裡以 app.module.ts 為例:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
  1. 自訂 Provider,Nest 提供了多種方式來自訂 Provider,都是透過展開式進行定義:

Value Provider

這類型的 Provider 主要是用來:

  • 提供常數 (Constant)。
  • 將外部函式庫注入到控制反轉容器。
  • 將 class 抽換成特定的模擬版本。

非類別型 token

事實上,Provider 的 token 不一定要使用 class,Nest 允許使用以下項目:

  • string
  • symbol
  • enum
那要如何使用呢?在展開式中使用 useValue 來配置。這裡以 app.module.ts 為例:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    {
      provide: AppService,
      useValue: {
        name: 'HAO'
      }
    }
  ],
})
export class AppModule {}
修改 app.controller.ts 來查看 token 為 AppService 的內容為何:

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {
    console.log(this.appService);
  }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
修改 app.controller.ts 來查看 token 為 AppService 的內容為何:

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {
    console.log(this.appService);
  }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
會發現注入的 `AppService` 變成我們指定的物件,會在終端機看到結果:

{ name: 'HAO' }
-------------------------------------------
這邊同樣以 `app.module.ts` 為例,我們指定 `token` 為字串 `HANDSOME_MAN`,並使用 `HAO` 作為值:

Class Provider

Factory Provider

image.png

image.png

汇出自订 Provider

在介绍共享模组的时候,有提到可以透过 Module 的 exports 将 Provider 汇出,那自订 Provider 要如何汇出呢?接着,我们把 Custom Provider 的 展开式用变数储存起来,再将该展开式放到 providers 与 exports 中:

import { Module } from '@nestjs/common';

const HANDSOME_HAO = {
  provide: 'HANDSOME_MAN',
  useValue: {
    name: 'HAO'
  }
};

@Module({
  providers: [
    HANDSOME_HAO
  ],
  exports: [
    HANDSOME_HAO
  ]
})
export class HandsomeModule {}

//AppModule 进行汇入,下方为 app.module.ts 的范例:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { HandsomeModule } from './handsome/handsome.module';

@Module({
  imports: [HandsomeModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

image.png

import { Module } from '@nestjs/common';

const HANDSOME_HAO = {
  provide: 'HANDSOME_MAN',
  useFactory: async () => {
    const getHAO = new Promise(resolve => {
      setTimeout(() => resolve({ name: 'HAO' }), 2000);
    });
    const HAO = await getHAO;
    return HAO;
  }
};

@Module({
  providers: [
    HANDSOME_HAO
  ],
  exports: [
    HANDSOME_HAO
  ]
})
export class HandsomeModule {}

image.png

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

接着去修改 `app.controller.ts` 的内容,替 `HANDSOME_MAN` 给定预设值:


import { Controller, Get, Inject, Optional } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    @Optional() @Inject('HANDSOME_MAN') private readonly handsomeMan = { name: '' }
    ) {
      console.log(this.handsomeMan);
  }

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}