一、什么是模块在 NestJS 中模块是用Module()装饰器注释的类。每个 NestJS 应用至少有一个根模块通常是AppModule。模块提供了编译时的上下文用于组织控制器、提供者服务、仓库等以及其他相关模块。模块的主要作用将相关的功能聚合在一起如用户模块、订单模块。声明模块内部的组件控制器、提供者哪些可以对外暴露哪些是私有的。管理模块之间的依赖关系导入其他模块的功能。支持动态模块实现可配置的模块。二、Module()装饰器配置项Module()接受一个对象包含以下常用属性属性作用providers由 Nest 注入器实例化的提供者服务、仓库、工厂等至少在当前模块中可用。controllers必须创建的控制器集合处理 HTTP 请求。imports导入其他模块中导出的提供者以便在当前模块中使用。exports导出当前模块中的提供者供其他导入本模块的模块使用。import { Module } from nestjs/common; import { UsersController } from ./users.controller; import { UsersService } from ./users.service; Module({ controllers: [UsersController], // 注册控制器 providers: [UsersService], // 注册服务 exports: [UsersService], // 导出 UsersService 供其他模块使用 }) export class UsersModule {}三、模块的基本用法1. 功能模块化按业务功能划分模块例如用户模块、产品模块、订单模块。src/ ├── users/ │ ├── users.module.ts │ ├── users.controller.ts │ ├── users.service.ts │ └── entities/ ├── products/ │ ├── products.module.ts │ ├── products.controller.ts │ └── products.service.ts └── app.module.tsusers.module.tsModule({ controllers: [UsersController], providers: [UsersService], exports: [UsersService], // 如果其他模块需要 UserService }) export class UsersModule {}app.module.ts导入这些功能模块Module({ imports: [UsersModule, ProductsModule], }) export class AppModule {}2. 共享模块NestJS 模块默认是单例的并且提供者默认是共享的。如果你想让一个模块的提供者被其他模块使用只需要在exports数组中列出它们。// common.module.ts Module({ providers: [CommonService, HelperService], exports: [CommonService], // 只导出 CommonServiceHelperService 对外不可见 }) export class CommonModule {}其他模块导入CommonModule后就可以注入CommonService但不能注入HelperService因为它未被导出。3. 全局模块如果希望一个模块到处可用无需在每个使用模块中导入可以使用Global()装饰器。全局模块通常用于基础设施如数据库连接、日志服务。import { Global, Module } from nestjs/common; Global() Module({ providers: [DatabaseService], exports: [DatabaseService], }) export class DatabaseModule {}现在任何模块无需导入DatabaseModule都可以直接注入DatabaseService。注意谨慎使用全局模块避免命名冲突和不清晰的依赖关系。四、模块的依赖注入模块本身也可以注入提供者但模块类通常不需要被注入。模块类可以有自己的构造函数并接收通过providers注册的服务但更常见的做法是将提供者注入到控制器或服务中。Module({ providers: [ConfigService], }) export class AppModule { constructor(private configService: ConfigService) { // 可以在模块类中使用注入的服务但实际业务中很少这样写 } }五、模块封装与作用域提供者作用域默认是模块作用域即提供者在所属模块内可见。只有被exports导出的提供者才能被其他模块使用。控制器作用域控制器必须在所属模块的controllers数组中声明不能跨模块直接使用除非通过路由导入其他模块的控制器但通常不会这样做。模块间通信通过导入导出提供者来实现功能共享而不是直接引用其他模块的控制器。六、动态模块动态模块允许你在导入时传递配置参数从而创建可定制的模块。动态模块可以返回一个动态的Module定义可以修改providers、exports等。示例可配置的日志模块// logger.module.ts import { Module, DynamicModule } from nestjs/common; import { LoggerService } from ./logger.service; Module({}) export class LoggerModule { static forRoot(options: { level: string }): DynamicModule { return { module: LoggerModule, providers: [ { provide: LOG_LEVEL, useValue: options.level, }, LoggerService, ], exports: [LoggerService], }; } }使用动态模块Module({ imports: [LoggerModule.forRoot({ level: debug })], }) export class AppModule {}NestJS 提供了几种约定方法名register(),forRoot(),forFeature()等用于不同场景如配置模块、异步模块。七、模块重导出你可以通过exports数组直接重导出其他模块这样导入当前模块的模块就能间接获得被重导出模块的提供者。Module({ imports: [CommonModule], exports: [CommonModule], // 重导出 CommonModule }) export class CoreModule {}这样任何导入CoreModule的模块都会自动获得CommonModule导出的提供者。八、最佳实践与常见模式1. 按功能域划分模块每个功能模块应包含自己的控制器、服务、实体、DTO 等保持高内聚低耦合。2. 使用共享模块集中管理公共组件创建一个SharedModule导入并导出公共服务如HelperService,DateService然后让其他模块导入SharedModule。3. 避免循环依赖如果模块 A 和模块 B 互相导入会导致循环依赖。解决方法将共享提供者提取到独立模块中。使用forwardRef(() Module)延迟引用不推荐应优先重构。4. 使用动态模块进行可配置集成对于数据库、缓存、消息队列等需要配置的集成提供动态模块方法如forRoot(),register()九、完整示例用户模块 数据库模块database.module.ts全局动态模块import { Global, Module, DynamicModule } from nestjs/common; import { createConnection } from typeorm; Global() Module({}) export class DatabaseModule { static forRoot(entities: Function[]): DynamicModule { const connectionProvider { provide: CONNECTION, useFactory: async () await createConnection({ type: mysql, host: localhost, port: 3306, username: root, password: password, database: test, entities, }), }; return { module: DatabaseModule, providers: [connectionProvider], exports: [connectionProvider], }; } }users.module.tsimport { Module } from nestjs/common; import { UsersController } from ./users.controller; import { UsersService } from ./users.service; import { User } from ./user.entity; Module({ imports: [DatabaseModule.forRoot([User])], // 传入实体 controllers: [UsersController], providers: [UsersService], }) export class UsersModule {}app.module.tsModule({ imports: [UsersModule], }) export class AppModule {}十、总结模块是 NestJS 架构的组织单元通过Module()声明。每个模块可以包含控制器、提供者并可以导入其他模块、导出自己的提供者。模块默认是单例作用域提供者默认是模块内共享的。使用Global()创建全局模块减少导入次数。动态模块允许在导入时配置模块实现高度可定制。良好的模块设计应当高内聚、低耦合按业务功能划分。