1. 程式人生 > 程式設計 >NestJs學習之旅(4)——模組系統

NestJs學習之旅(4)——模組系統

歡迎持續關注NestJs之旅系列文章

二維碼

模組

NestJs中模組是構建和組織業務單元的基本元素。使用@Module()裝飾模組來宣告該模組的元資訊:

  • 本模組匯出哪些服務提供者
  • 本模組匯入了哪些依賴模組
  • 本模組提供了哪些控制器

每個NestJs至少有一個跟模組,這個就是app.module.ts定義的。根模組一般不放具體的業務邏輯,具體業務邏輯應該下沉到各個子業務模組去做。

比如我們開發一個商城系統,該系統有以下業務模組:

  • 訂單中心
  • 使用者中心
  • 支付中心
  • 商品中心
  • 物流中心

那我們可以定義以下的模組結構:

|-- app.module.ts
|-- order
    |-- order.module.ts
    |-- services
        |-- order.service.ts
    |-- controllers
        |-- order.controller.ts
|-- user
    |-- user.module.ts
    |-- services
        |-- user.service.ts
    |-- controllers
        |-- user.controller.ts
|-- pay
    |-- pay.module.ts
    |-- services
        |-- wepay.service.ts
        |-- alipay.service.ts
        |-- pay.service.ts
    |-- controller
        |-- pay.controller.ts
...
複製程式碼

模組化有以下優點:

  • 業務低耦合
  • 邊界清晰
  • 便於排查錯誤
  • 便於維護

模組宣告與配置

@Module()裝飾的類為模組類,該裝飾器的典型用法如下:

@Module({
    providers: [UserService],controllers: [UserController],imports: [OrderModule],exports: [UserService]
})
export class UserModule {

}
複製程式碼
引數名稱 說明
proviers 服務提供者列表,本模組可用,可以自動注入
controllers 控制器列表,本模組可用,用來繫結路由訪問
imports 本模組匯入的模組,如果需要使用到其他模組的服務提供者,此處必須匯入其他模組
exports 本模組匯出的服務提供者,只有在此處定義的服務提供者才能在其他模組使用

模組重匯出

ts中有以下用法:

// a.ts
export interface A {

}
複製程式碼
// index.ts
export * from './a';
複製程式碼

我們在使用的時候直接使用以下程式碼即可,方面封裝

import {A} from './index'
複製程式碼

NestJs中的模組也有類似用法,比如我們定義了兩個基本模組,這兩個基本模組用的時候基本都是一起匯入的,此時我們通過模組重匯出將其封裝到一個叫CoreModule

,其他地方直接匯入CoreModule即可。

@Module({
    providers: [CommonService],exports: [CommonService]
})
export class CommonModule {}
複製程式碼
@Module({
    providers: [Util],exports: [Util]
})
export class UtilModule {}
複製程式碼
@Module({
    imports: [CommonModule,UtilModule],exports: [CommonModule,UtilModule]
})
export class CoreModule {}
複製程式碼

模組初始化與依賴注入

如果需要在模組例項化的時候執行一些邏輯,而且該邏輯有外部依賴的時候,可以通過以下方式處理

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Module({
  controllers: [UserController],providers: [UserService],})
export class catsModule {
  constructor(private readonly userService: UserService) { // 沒有@Inject
    // 呼叫userService
  }
}
複製程式碼

全域性模組

上面定義的模組都是需要手動imports進來的,如果有些模組是使用率很高的,比如工具模組,此時可以宣告為全域性模組。

使用@Global()即可宣告全域性模組。

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Global()
@Module({
  controllers: [UserController],})
export class catsModule {
  
}
複製程式碼

動態模組

上面定義的都是靜態模組,如果我們需要動態宣告我們的模組,比如資料庫模組,連線成功我才返回模組,此時需要使用動態模組來處理。

使用模組名.forRoot()方法來返回模組定義,通過該方式定義的即為動態模組。

@Module({
    providers: [DatabaseProvider]
})
export class DatabaseModule {
    static async forRoot(env: string) {
         const provider =  createDatabaseProvider(env); // 根據環境變數連線不同的資料庫
         return {
             module: DatabaseModule,providers: [provider],exports: [provider]
         }
    }
}
複製程式碼
// user.module.ts
@Module({
    imports: [DatabaseModule.forRoot('production')]
})
export class UserModule {}
複製程式碼

生產環境下的姿勢

上面有一個商城系統的模組例子,當我們的業務模組開發完畢之後,需要將其註冊到AppModule,這樣才能生效,這個也有個好處,有點像插拔的例子,當需要下掉一個業務時,業務程式碼不動,在AppModule取消註冊即可。

@Module({
    imports:[UserModule,GoodsModule,OrderModule,PayModule]
})
export class AppModule {}
複製程式碼

結尾

模組系統是NestJs另一個重要的特性,個人認為是基於DDD思想的,每個模組就是一個單獨的領域業務,可以由一個小組去獨立開發。多個模組時可以同時開發,如果有依賴問題的話,可以先把模組和響應的interface公開出去,別人正常呼叫你的interface,當實現類開發完畢之後NestJs會自動注入該實現類,呼叫方的程式碼不用更改。

如果您覺得有所收穫,分享給更多需要的朋友,謝謝!

如果您想交流關於NestJs更多的知識,歡迎加群討論!

image