从零开始Node之旅——Nest.js 模块系统(Modules)

Nest.js 的模块系统是其架构的核心组成部分,它借鉴了 Angular 的模块设计思想,通过模块化的方式组织代码,实现关注点分离、依赖管理和代码复用。模块系统让大型应用的结构更加清晰,便于维护和扩展。

一、模块的核心概念与作用

  1. 关注点分离
    将相关功能(如用户管理、认证、日志等)封装到独立模块中,避免代码耦合。
  2. 依赖管理
    明确模块间的依赖关系,通过导入(imports)和导出(exports)控制功能共享。
  3. 依赖注入作用域
    模块定义了 provider 的作用域,确保服务在模块内高效共享。
  4. 代码组织
    模块系统帮助团队按照功能域组织代码,提升项目可维护性。

二、模块的基本结构与创建

Nest.js 模块通过 @Module 装饰器定义,核心属性包括:

  • imports:导入其他模块,获取其导出的功能
  • providers:模块内的服务、工厂等依赖注入对象
  • controllers:模块关联的控制器
  • exports:导出模块内的 providers 或导入的模块,供其他模块使用

示例:创建一个基础模块

typescript 复制代码
// user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { DatabaseModule } from '../database/database.module';

@Module({
  imports: [DatabaseModule], // 导入数据库模块
  controllers: [UserController], // 注册控制器
  providers: [UserService], // 注册服务
  exports: [UserService], // 导出服务供其他模块使用
})
export class UserModule {}

三、模块的核心属性详解

  1. imports:模块依赖导入
    当模块需要使用其他模块的功能时,通过 imports 导入目标模块。例如:
kotlin 复制代码
@Module({
  imports: [AuthModule, DatabaseModule], // 导入多个模块
})
export class UserModule {}
  1. exports:功能导出
    通过 exports 声明模块内可被其他模块使用的 providers 或导入的模块:
less 复制代码
@Module({
  imports: [DatabaseModule],
  providers: [UserService],
  exports: [UserService, DatabaseModule], // 导出自身服务和导入的模块
})
export class UserModule {}
  1. providers:模块内服务注册
    providers 包含模块所需的所有依赖注入对象(服务、仓库、工厂等),这些对象会在模块内共享:
less 复制代码
@Module({
  providers: [
    UserService,
    {
      provide: 'USER_REPOSITORY',
      useClass: UserRepository,
    },
  ],
})
export class UserModule {}
  1. controllers:控制器注册
    controllers 声明模块关联的控制器,控制器会接收请求并调用模块内的服务:
kotlin 复制代码
@Module({
  controllers: [UserController, AdminController],
})
export class UserModule {}

controllersproviders最大的不同是,每次请求都会创建一个controllers,而providers是单例模式,全局唯一。

四、模块间的依赖与共享

  1. 模块导入与功能共享
    当模块 A 导入模块 B 后,模块 A 可以使用模块 B 导出的所有功能:
kotlin 复制代码
// app.module.ts
@Module({
  imports: [UserModule, AuthModule], // 导入用户模块和认证模块
})
export class AppModule {}
  1. 循环依赖处理
    Nest.js 支持循环依赖,但应尽量避免。若必须使用,可通过以下方式处理:
kotlin 复制代码
// user.module.ts
@Module({
  imports: [
    forwardRef(() => AuthModule), // 使用forwardRef解决循环依赖
  ],
})
export class UserModule {}

五. 类与模块的关系

模块的核心作用是将功能相关的类聚合在一起 ,避免代码散落在项目各处。例如:

一个用户管理模块(UserModule)会包含用户相关的控制器(UserController)、服务(UserService)、守卫(AuthGuard)等类,这些类共同完成用户管理的功能。

less 复制代码
// user.module.ts(模块定义)
@Module({
  controllers: [UserController],  // 声明模块包含的控制器类
  providers: [UserService, AuthGuard],  // 声明模块包含的服务、守卫类
  imports: [DatabaseModule],  // 导入其他模块的类(如数据库连接服务)
  exports: [UserService],  // 导出服务类供其他模块使用
})
export class UserModule {}

六、根模块(Root Module)

每个 Nest.js 应用都有一个根模块(通常为 AppModule),作为应用的入口:

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

@Module({
  imports: [UserModule, AuthModule], // 导入所有子模块
})
export class AppModule {}

main.ts 中引导根模块:

javascript 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

七、动态模块(Dynamic Modules)

动态模块允许在运行时配置模块,常用于需要动态参数的服务(如数据库连接、第三方服务集成)。通过 forRootforFeature 方法实现:

arduino 复制代码
// database.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { DatabaseService } from './database.service';

@Module({})
export class DatabaseModule {
  // 用于根模块的全局配置
  static forRoot(config: DatabaseConfig): DynamicModule {
    return {
      module: DatabaseModule,
      providers: [
        {
          provide: 'DATABASE_CONFIG',
          useValue: config,
        },
        DatabaseService,
      ],
      exports: [DatabaseService],
    };
  }

  // 用于功能模块的局部配置
  static forFeature(): DynamicModule {
    return {
      module: DatabaseModule,
      exports: [DatabaseService],
    };
  }
}

使用动态模块:

less 复制代码
// app.module.ts
@Module({
  imports: [
    DatabaseModule.forRoot({
      host: 'localhost',
      port: 5432,
      username: 'user',
    }),
  ],
})
export class AppModule {}
相关推荐
贩卖纯净水.1 分钟前
webpack其余配置
前端·webpack·node.js
保持学习ing1 小时前
SpringBoot前后台交互 -- 登录功能实现(拦截器+异常捕获器)
java·spring boot·后端·ssm·交互·拦截器·异常捕获器
十年老菜鸟2 小时前
spring boot源码和lib分开打包
spring boot·后端·maven
白宇横流学长2 小时前
基于SpringBoot实现的课程答疑系统设计与实现【源码+文档】
java·spring boot·后端
程序猿小D3 小时前
第24节 Node.js 连接 MongoDB
数据库·mongodb·npm·node.js·编辑器·vim·express
加瓦点灯3 小时前
什么?工作五年还不了解SafePoint?
后端
无知好快_Sosoo浪浪3 小时前
Node.js版本管理
node.js
他日若遂凌云志4 小时前
Lua 模块系统的前世今生:从 module () 到 local _M 的迭代
后端
David爱编程4 小时前
Docker 安全全揭秘:防逃逸、防漏洞、防越权,一篇学会容器防御!
后端·docker·容器
小码编匠4 小时前
WinForm 工业自动化上位机通用框架:注册登录及主界面切换实现
后端·c#·.net