Nest:动态和全局模块

Nest.js 是一个高度模块化的框架,它鼓励使用模块(Module)来组织代码,以实现不同功能区块的隔离。

模块封装最佳建议:

  • 单一职责原则:每个模块应该只关注一个功能和任务。
  • 封装:模块内部的实现应该对外界隐藏,只通过 exports 露出必要的部分给外界使用。
  • 配置与环境隔离:使用配置模块或服务来处理不同环境(开发、测试、生产)的配置。这有助于将配置管理从业务逻辑中解耦。

模块相互配合

导出 PersonService 以便其他模块使用:

导入 PersonModule 以使用它的 PersonService:

在 AppController 就可以使用导入的PersonMoudle 的 PersonService,以及自身 providers 数组的 AppService:

模块重导出

有时候我们希望在导出一个模块的同时,也重新导出它所导入的模块。这样可以让这个模块的消费者直接使用它依赖的模块的功能,而无需显式地导入它们。

在 Nest.js 中,可以使用 exports 数组来重导出模块:

typescript 复制代码
// email.module.ts
@Module({
  imports: [CommonModule],
  providers: [EmailService],
  exports: [EmailService, CommonModule] // 重导出 CommonModule
})
export class EmailModule {}

在上面的代码中,EmailModule 不仅导出了它自己的 EmailService,也重导出了它导入的 CommonModule

这意味着导入 EmailModule 的模块也会自动导入 CommonModule,并可以使用其提供的服务。

这种重导出机制在组织大型应用程序时非常有用,因为它可以减少模块间的耦合,同时简化外部模块的导入过程。

全局模块

全局模块AuthModule 被设置为全局模块,它的 AuthService 可以在应用中的任何地方使用,而无需显式导入 AuthModule

使用 @Global 声明成全局模块并 export 想导出的 Service。

typescript 复制代码
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [AuthModule],
  // ...其他配置
})
export class AppModule {}

一旦 AuthModule 被导入到根模块,它内部导出的模块就可以直接在其他模块使用,其他不用 imports 其 Module 便可使用其 service。

全局模块通常用于那些提供跨应用程序共享的基础服务的功能,例如配置服务、数据库服务或任何其他需要在多个模块之间共享的服务。

注意:避免过度使用全局模块,代码可读性更好。

动态模块

动态模块允许在模块被导入时动态配置提供者(providers)、控制器(controllers)和导出(exports)。

这种方式非常适合需要根据不同环境或配置动态更改其行为的模块。

新建 Nest 项目:

bash 复制代码
nest new dynamic-module -p npm

创建 CRUD 模块:

bash 复制代码
nest g resource dynamicModule

此时导入的 DynamicModuleModule 内容都是固定:

我们需要导入的时候给其传入一些参数怎么办?

这样写:

多了一个 module 属性指向当前的模块类,即 DynamicModuleModule

我们给 DynamicModuleModule 加一个 register 的静态方法,返回模块定义的对象,外部传入的 options 参数对象会作为一个新的 provider。

导入时配置:

使用 @Inject 注入依赖:

访问 localhost:3000,控制台打印:

这就是动态模块。

上面静态方法 register 方法可以任意取名,但 nest 约定了一些方法名:

  • register:用一次模块传一次配置
  • forRoot:根模块(AppModule)配置一次,例如数据库连接、核心服务等。
  • forRootAsync:类似于 forRoot,但用于异步配置,允许从异步服务中获取配置信息。它通常接收一个 useFactory 这个返回配置对象的工厂函数。
  • forFeature:用 forRoot 固定整体模块,用于局部的时候,可能需要再传一些配置。比如用 forRoot 指定了数据库链接信息,再用 forFeature 指定某个模块访问哪个数据库和表。
  • forFeatureAsync: 类似于 forFeature,但用于异步配置特定功能。

异步动态模块

如果需要异步地提供配置,可以使用 forRootAsync 方法。

这个方法通常与工厂函数或类一起使用,以便异步地解析配置数据,然后再创建模块:

typescript 复制代码
@Module({})
export class DynamicModule {
  static forRootAsync(options: DynamicModuleAsyncOptions): DynamicModule {
    return {
      module: DynamicModule,
      imports: options.imports || [],
      providers: [
        {
          provide: 'CONFIG_OPTIONS',
          useFactory: options.useFactory,
          inject: options.inject || [],
        },
        DynamicService,
      ],
      exports: [DynamicService],
    };
  }
}

在这个异步版本中,useFactory 是一个工厂函数,它可以异步地返回配置对象。
inject 属性是一个数组,它定义了工厂函数的依赖项,这些依赖项将被注入到工厂函数中。

相关推荐
wno704几秒前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc3 分钟前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
aramae1 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
计算机魔术师1 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen2 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒2 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
分支预测失败2 小时前
RISC-V 时间子系统深度专题:mtime 访问路径、SBI 定时器与 Linux tickless 协同
后端
65岁退休Coder2 小时前
PI Agent 开发一个生产级 Harness
后端·node.js·agent
前端snow3 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林8183 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器