NestJS模块化架构
一、模块化概念
1.1 什么是模块化
概念说明
模块化是 NestJS 组织应用的核心方式。所有的功能块都用模块来组织,类似于前端的组件化概念,但颗粒度更大。y'y
前端类比理解
code
前端组件化 vs 后端模块化:
前端组件化:
│
├── 组件(Component)
│ ├── 颗粒度:小(按钮、表单、列表)
│ ├── 作用:UI 层面的复用
│ └── 组织:组合成页面
│
└── 目的
└── 减少 UI 重复代码
后端模块化:
│
├── 模块(Module)
│ ├── 颗粒度:大(用户模块、订单模块)
│ ├── 作用:功能层面的组织
│ └── 组织:组合成应用
│
└── 目的
└── 减少业务重复代码
类比理解:
• 模块 ≈ 组件(但颗粒度更大)
• 模块组合 ≈ 组件组合
• 都是为了复用和解耦1.2 积木类比理解
形象理解
code
积木类比:
单个积木:
│
├── 特点
│ ├── 独立存在
│ ├── 有特定形状和功能
│ └── 可单独使用
│
└── 对应
└── 单个模块(如用户模块)
组合积木:
│
├── 特点
│ ├── 多个积木有机组合
│ ├── 形成更大的结构
│ └── 分开独立,组合成整体
│
└── 对应
└── 整个应用(多个模块组合)
核心理念:
• 分开:各自独立
• 组合:浑然一体
• 目的:减少重复、提升可维护性二、NestJS 模块组织结构
2.1 模块依赖关系图
官方示例图解
code
NestJS 模块组织结构:
┌─────────────────────────────────────────────────────────┐
│ Application Module(根模块) │
│ AppModule │
└───────────┬─────────────────────┬───────────────────────┘
│ │
┌───────┴───────┐ ┌───────┴───────┐ ┌──────────┐
│ Users Module │ │ Orders Module │ │ Chat Msg │
│ 用户模块 │ │ 订单模块 │ │ 消息模块 │
└───────────────┘ └───────┬───────┘ └──────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌───────┴───────┐ ┌───┴────┐ ┌────┴─────┐
│ Feature1 Mdl │ │Feature2│ │Feature 3 │
│ 功能一模块 │ │ 功能二 │ │ 功能三 │
└───────────────┘ └────────┘ └──────────┘
依赖关系说明:
│
├── 一级模块
│ ├── Users Module(用户模块)
│ ├── Orders Module(订单模块)
│ └── Chat Message Module(消息模块)
│
├── 二级模块
│ ├── Feature1 Module(功能一模块)← Orders Module 依赖
│ ├── Feature2 Module(功能二模块)← Orders Module 依赖
│ └── Feature3 Module(功能三模块)← Chat Module 依赖
│
└── 依赖方向
└── 箭头方向 = import 方向2.2 模块导入导出关系
ES6 类比
typescript
// ========== ES6 模块导入导出 ==========
// module-a.ts
export const serviceA = { /* ... */ };
// module-b.ts
import { serviceA } from './module-a';
export const serviceB = { /* ... */ };
// ========== NestJS 模块导入导出 ==========
// users.module.ts
@Module({
providers: [UsersService], // 提供 Service
exports: [UsersService], // 导出 Service
})
export class UsersModule {}
// orders.module.ts
@Module({
imports: [UsersModule], // 导入 UsersModule
providers: [OrdersService],
})
export class OrdersModule {}
// 关键点:
// • imports:导入其他模块
// • exports:导出给其他模块使用
// • 与 ES6 语法非常类似三、@Module 装饰器详解
3.1 四大核心属性
@Module 装饰器结构
typescript
import { Module } from '@nestjs/common';
@Module({
imports: [], // 导入其他模块
controllers: [], // 控制器
providers: [], // 服务提供者
exports: [], // 导出给其他模块使用
})
export class AppModule {}四大属性详解
| 属性 | 类型 | 说明 | 类比理解 |
|---|---|---|---|
| imports | Module[] | 导入其他模块 | ES6 的 import |
| controllers | Controller[] | 处理请求的控制器 | 路由层 |
| providers | Provider[] | 服务提供者(Service) | 业务逻辑层 |
| exports | Provider[] | 导出给其他模块使用 | ES6 的 export |
3.2 providers 深入理解
providers 的本质
code
Providers(提供者)理解:
│
├── 本质
│ ├── 依赖注入中的实例化对象
│ ├── 做脏活累活的角色
│ └── 在模块中实现共享
│
├── 典型代表
│ ├── Service(服务)
│ ├── Repository(仓库)
│ ├── Factory(工厂)
│ └── Helper(辅助工具)
│
├── 注意事项
│ ├── providers 不能导入模块
│ ├── 可能导致循环依赖
│ └── 由框架自动管理实例化
│
└── 简化理解
└── providers = Service 层的容器代码示例
typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
// 控制器:处理请求
controllers: [UsersController],
// 提供者:业务逻辑
providers: [UsersService],
// 导出:供其他模块使用
exports: [UsersService],
})
export class UsersModule {}
// 使用示例
// src/orders/orders.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';
@Module({
// 导入 UsersModule,可以使用其导出的 UsersService
imports: [UsersModule],
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}
// orders.service.ts
import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';
@Injectable()
export class OrdersService {
// 可以注入 UsersService(因为 UsersModule 导出了它)
constructor(private readonly usersService: UsersService) {}
async createOrder(userId: number, orderData: any) {
// 使用 UsersService
const user = await this.usersService.findOne(userId);
// ...
}
}3.3 TypeScript 类型提示
IDE 友好性
typescript
// 按 Command/Ctrl 点击 @Module 装饰器
// @nestjs/common/decorators/modules/module.decorator.ts
export declare function Module(metadata: ModuleMetadata): ClassDecorator;
// @nestjs/common/interfaces/modules/module-metadata.interface.ts
export interface ModuleMetadata {
/**
* 可选的导入模块列表
* 这些模块中导出的提供者在此模块中可用
*/
imports?: Array<Type<any> | DynamicModule | Promise<DynamicModule>>;
/**
* 要实例化的控制器列表
*/
controllers?: Array<Type<any>>;
/**
* 要实例化的提供者列表
* 它们可以注入到此模块的其他组件中
*/
providers?: Provider[];
/**
* 要导出的提供者列表
* 它们应该在此模块导入的其他模块中可用
*/
exports?: Array<DynamicModule | Promise<DynamicModule> | string | symbol | Provider | ForwardReference>;
}
// TypeScript 提供完整的类型提示和注释
// 不确定如何使用时,可以查看接口定义四、四种模块类型
4.1 功能模块(Feature Module)
概念说明
功能模块是按业务功能划分的模块,如用户模块、订单模块、消息模块等。
特点
code
功能模块特点:
│
├── 按业务功能划分
│ ├── 用户模块(UsersModule)
│ ├── 订单模块(OrdersModule)
│ └── 消息模块(ChatModule)
│
├── 高内聚
│ ├── 相关功能聚合在一起
│ └── 边界清晰
│
└── 可组合
└── 多个功能模块组成完整应用代码示例
typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UsersRepository } from './users.repository';
@Module({
controllers: [UsersController],
providers: [UsersService, UsersRepository],
exports: [UsersService],
})
export class UsersModule {}
// src/orders/orders.module.ts
import { Module } from '@nestjs/common';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';
@Module({
controllers: [OrdersController],
providers: [OrdersService],
exports: [OrdersService],
})
export class OrdersModule {}
// src/chat/chat.module.ts
import { Module } from '@nestjs/common';
import { ChatController } from './chat.controller';
import { ChatService } from './chat.service';
@Module({
controllers: [ChatController],
providers: [ChatService],
exports: [ChatService],
})
export class ChatModule {}4.2 共享模块(Shared Module)
概念说明
共享模块用于存放各个模块共用的功能,类似于前端的公共组件库。
特点
code
共享模块特点:
│
├── 跨模块共享
│ ├── 多个模块共用
│ └── 避免代码重复
│
├── 导出公共 Provider
│ └── Service、Helper 等
│
└── 被其他模块导入
└── import 后即可使用代码示例
typescript
// src/common/common.module.ts
import { Module } from '@nestjs/common';
import { LoggerService } from './logger.service';
import { ConfigService } from './config.service';
import { UtilsService } from './utils.service';
@Module({
providers: [LoggerService, ConfigService, UtilsService],
exports: [LoggerService, ConfigService, UtilsService], // 导出公共 Service
})
export class SharedModule {}
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { SharedModule } from '../common/common.module';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
imports: [SharedModule], // 导入共享模块
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
// users.service.ts
import { Injectable } from '@nestjs/common';
import { LoggerService } from '../common/logger.service';
@Injectable()
export class UsersService {
// 可以使用 SharedModule 导出的 Service
constructor(private readonly logger: LoggerService) {}
findAll() {
this.logger.log('查询所有用户');
// ...
}
}4.3 全局模块(Global Module)
概念说明
全局模块一旦注册,其导出的 Provider 在所有模块中都可用,无需重复导入。
特点
code
全局模块特点:
│
├── 全局可用
│ ├── 无需在每个模块中导入
│ └── 类似全局变量
│
├── 一次性注册
│ └── 在根模块导入一次即可
│
└── 适用场景
├── 数据库连接
├── 日志服务
└── 配置服务代码示例
typescript
// src/database/database.module.ts
import { Module, Global } from '@nestjs/common';
import { DatabaseService } from './database.service';
@Global() // 声明为全局模块
@Module({
providers: [DatabaseService],
exports: [DatabaseService], // 导出后全局可用
})
export class DatabaseModule {}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { UsersModule } from './users/users.module';
@Module({
imports: [
DatabaseModule, // 只需在根模块导入一次
UsersModule,
],
})
export class AppModule {}
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../database/database.service';
@Injectable()
export class UsersService {
// 无需导入 DatabaseModule,直接注入即可
constructor(private readonly database: DatabaseService) {}
findAll() {
return this.database.query('SELECT * FROM users');
}
}
// 注意:
// 全局模块虽然方便,但会降低代码可读性
// 建议只在真正全局的服务上使用(如数据库、日志、配置)4.4 动态模块(Dynamic Module)
概念说明
动态模块支持按需初始化,类似于前端的懒加载,在需要使用时才进行初始化。
特点
code
动态模块特点:
│
├── ⏱ 按需初始化
│ ├── 使用时才初始化
│ └── 减少启动时间
│
├── 动态配置
│ ├── 运行时传入配置
│ └── 灵活可配置
│
├── 前端类比
│ ├── 图片懒加载
│ ├── 路由懒加载
│ └── 组件懒加载
│
└── 记忆技巧
└── 动态模块 = 懒加载模块代码示例
typescript
// src/database/database.module.ts
import { Module, DynamicModule, Global } from '@nestjs/common';
import { DatabaseService } from './database.service';
export interface DatabaseModuleOptions {
host: string;
port: number;
username: string;
password: string;
database: string;
}
@Global()
@Module({})
export class DatabaseModule {
/**
* 动态注册方法
* @param options 数据库配置
* @returns DynamicModule
*/
static forRoot(options: DatabaseModuleOptions): DynamicModule {
return {
module: DatabaseModule,
providers: [
{
provide: 'DATABASE_OPTIONS',
useValue: options,
},
DatabaseService,
],
exports: [DatabaseService],
};
}
/**
* 异步注册方法
* @param options 异步配置
* @returns DynamicModule
*/
static forRootAsync(options: {
useFactory: (...args: any[]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;
inject?: any[];
}): DynamicModule {
return {
module: DatabaseModule,
providers: [
{
provide: 'DATABASE_OPTIONS',
useFactory: options.useFactory,
inject: options.inject || [],
},
DatabaseService,
],
exports: [DatabaseService],
};
}
}
// ========== 使用示例 ==========
// src/app.module.ts
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
// 方式一:同步配置
DatabaseModule.forRoot({
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'test',
}),
// 方式二:异步配置(推荐)
DatabaseModule.forRootAsync({
useFactory: (configService: ConfigService) => ({
host: configService.get('DATABASE_HOST'),
port: configService.get('DATABASE_PORT'),
username: configService.get('DATABASE_USERNAME'),
password: configService.get('DATABASE_PASSWORD'),
database: configService.get('DATABASE_NAME'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}
// forRoot 和 forRootAsync 的命名约定:
// • forRoot:静态配置
// • forRootAsync:异步配置
// • 这是 NestJS 社区约定俗成的命名方式动态模块的实际应用
typescript
// TypeORM 动态模块示例
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'test',
entities: [],
synchronize: true,
}),
],
})
export class AppModule {}
// TypeOrmModule.forRoot() 就是动态模块
// 只有在应用启动时才会初始化数据库连接五、模块组织最佳实践
5.1 目录结构规范
推荐的项目结构
code
project-root/
│
├── src/
│ ├── common/ # 公共模块
│ │ ├── common.module.ts # 共享模块
│ │ ├── filters/ # 过滤器
│ │ ├── guards/ # 守卫
│ │ ├── interceptors/ # 拦截器
│ │ ├── pipes/ # 管道
│ │ ├── decorators/ # 自定义装饰器
│ │ └── interfaces/ # 公共接口
│ │
│ ├── config/ # 配置模块
│ │ ├── config.module.ts
│ │ └── configuration.ts
│ │
│ ├── database/ # 数据库模块
│ │ ├── database.module.ts
│ │ └── migrations/
│ │
│ ├── users/ # 用户模块(功能模块)
│ │ ├── users.module.ts
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── users.repository.ts
│ │ ├── dto/
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ ├── entities/
│ │ │ └── user.entity.ts
│ │ └── interfaces/
│ │ └── user.interface.ts
│ │
│ ├── orders/ # 订单模块(功能模块)
│ │ ├── orders.module.ts
│ │ ├── orders.controller.ts
│ │ ├── orders.service.ts
│ │ └── ...
│ │
│ ├── app.module.ts # 根模块
│ └── main.ts # 应用入口
│
├── test/ # 测试文件
├── nest-cli.json # NestJS CLI 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 项目依赖5.2 模块划分原则
code
模块划分原则:
│
├── 按业务功能划分
│ ├── 用户模块(UsersModule)
│ ├── 订单模块(OrdersModule)
│ ├── 商品模块(ProductsModule)
│ └── 支付模块(PaymentsModule)
│
├── 高内聚低耦合
│ ├── 相关功能聚合在一个模块
│ ├── 模块之间依赖最小化
│ └── 避免循环依赖
│
├── 单一职责
│ ├── 每个模块只负责一个业务领域
│ ├── 不要创建"上帝模块"
│ └── 合理拆分大型模块
│
└── 共享逻辑提取
├── 公共功能放入 SharedModule
├── 全局服务放入 GlobalModule
└── 避免重复代码5.3 避免循环依赖
循环依赖问题
typescript
// 循环依赖示例
// users.module.ts
@Module({
imports: [OrdersModule], // UsersModule 依赖 OrdersModule
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
// orders.module.ts
@Module({
imports: [UsersModule], // OrdersModule 依赖 UsersModule
providers: [OrdersService],
exports: [OrdersService],
})
export class OrdersModule {}
// 问题:UsersModule ⇄ OrdersModule 形成循环依赖解决方案
typescript
// 解决方案一:使用 forwardRef
// users.module.ts
import { Module, forwardRef } from '@nestjs/common';
@Module({
imports: [forwardRef(() => OrdersModule)],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
// orders.module.ts
import { Module, forwardRef } from '@nestjs/common';
@Module({
imports: [forwardRef(() => UsersModule)],
providers: [OrdersService],
exports: [OrdersService],
})
export class OrdersModule {}
// 解决方案二:提取共享模块
// common.module.ts
@Module({
providers: [SharedService],
exports: [SharedService],
})
export class SharedModule {}
// users.module.ts
@Module({
imports: [SharedModule], // 依赖 SharedModule 而非 OrdersModule
providers: [UsersService],
})
export class UsersModule {}
// orders.module.ts
@Module({
imports: [SharedModule], // 依赖 SharedModule 而非 UsersModule
providers: [OrdersService],
})
export class OrdersModule {}
// 解决方案三:重新设计架构(推荐)
// 检查是否真的需要相互依赖,可能需要重构业务逻辑六、完整项目示例
6.1 根模块配置
main.ts - 应用入口
typescript
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 全局验证管道
app.useGlobalPipes(new ValidationPipe());
// 全局前缀
app.setGlobalPrefix('api/v1');
// 启用 CORS
app.enableCors();
await app.listen(3000);
console.log('Application is running on: http://localhost:3000/api/v1');
}
bootstrap();app.module.ts - 根模块
typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
// 导入功能模块
import { UsersModule } from './users/users.module';
import { OrdersModule } from './orders/orders.module';
import { AuthModule } from './auth/auth.module';
// 导入共享模块
import { SharedModule } from './common/common.module';
// 导入数据库模块
import { DatabaseModule } from './database/database.module';
// 导入控制器和服务
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
// ========== 全局配置 ==========
ConfigModule.forRoot({
isGlobal: true, // 全局配置
envFilePath: '.env',
}),
// ========== 数据库配置(动态模块)==========
DatabaseModule.forRoot({
type: 'mysql',
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT, 10),
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
entities: [],
synchronize: true,
}),
// ========== 共享模块 ==========
SharedModule,
// ========== 功能模块 ==========
UsersModule,
OrdersModule,
AuthModule,
],
// 根模块的控制器
controllers: [AppController],
// 根模块的服务
providers: [AppService],
})
export class AppModule {}app.controller.ts - 根控制器
typescript
// src/app.controller.ts
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();
}
@Get('health')
healthCheck() {
return {
status: 'ok',
timestamp: new Date().toISOString(),
};
}
}app.service.ts - 根服务
typescript
// src/app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}6.2 完整功能模块示例
用户模块完整结构
typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UsersRepository } from './users.repository';
import { User } from './entities/user.entity';
import { SharedModule } from '../common/common.module';
@Module({
imports: [
TypeOrmModule.forFeature([User]), // 注册实体
SharedModule, // 导入共享模块
],
controllers: [UsersController],
providers: [UsersService, UsersRepository],
exports: [UsersService], // 导出供其他模块使用
})
export class UsersModule {}
// src/users/users.controller.ts
import {
Controller,
Get,
Post,
Body,
Param,
Put,
Delete,
UseGuards,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@Controller('users')
@UseGuards(JwtAuthGuard) // 控制器级别的守卫
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}
// src/users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { LoggerService } from '../common/logger.service';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly logger: LoggerService, // 从 SharedModule 注入
) {}
async findAll(): Promise<User[]> {
this.logger.log('查询所有用户');
return this.userRepository.find();
}
async findOne(id: number): Promise<User> {
const user = await this.userRepository.findOne({ where: { id } });
if (!user) {
throw new NotFoundException(`用户 #${id} 不存在`);
}
return user;
}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = this.userRepository.create(createUserDto);
return this.userRepository.save(user);
}
async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
const user = await this.findOne(id);
Object.assign(user, updateUserDto);
return this.userRepository.save(user);
}
async remove(id: number): Promise<void> {
const user = await this.findOne(id);
await this.userRepository.remove(user);
}
}
// src/users/entities/user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('users')
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 100 })
name: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
@Column({ default: true })
isActive: boolean;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
// src/users/dto/create-user.dto.ts
import { IsString, IsEmail, MinLength, MaxLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
@MaxLength(100)
name: string;
@IsEmail()
email: string;
@IsString()
@MinLength(6)
password: string;
}
// src/users/dto/update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}七、四种模块类型对比
7.1 对比表
| 模块类型 | 特点 | 应用场景 | 示例 |
|---|---|---|---|
| 功能模块 | 按业务功能划分 | 业务功能 | UsersModule、OrdersModule |
| 共享模块 | 跨模块共享 | 公共功能 | SharedModule、CommonModule |
| 全局模块 | 全局可用,无需导入 | 数据库、日志、配置 | DatabaseModule、LoggerModule |
| 动态模块 | 按需初始化,灵活配置 | 懒加载、运行时配置 | DatabaseModule.forRoot() |
7.2 选择指南
code
模块类型选择指南:
│
├── 功能模块
│ └── 需要独立业务功能时使用
│
├── 共享模块
│ └── 多个模块需要共用某个 Service 时使用
│
├── 全局模块
│ └── 全局通用服务(数据库、日志、配置)时使用
│
└── ⏱ 动态模块
└── 需要按需初始化或动态配置时使用八、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Service 无法注入 | 未在 providers 中注册 | 在 Module 的 providers 中添加 Service |
| 无法使用其他模块的 Service | 未导入模块或模块未导出 Service | import 模块 + exports Service |
| 循环依赖错误 | A 依赖 B,B 依赖 A | 使用 forwardRef 或重新设计架构 |
| 全局模块不生效 | 未使用 @Global() 装饰器 | 添加 @Global() 装饰器 |
| 动态模块配置无效 | forRoot 参数错误 | 检查配置格式和参数类型 |
| providers 导入模块 | 误解 providers 的作用 | providers 只能注册 Provider,不能导入 Module |
| 模块重复导入 | 不必要的重复导入 | 检查 imports,移除重复项 |
| Service 实例不共享 | 多个模块分别实例化 | 使用 SharedModule 或 GlobalModule |
九、学习要点总结
核心要点
- 模块化本质:类似于前端组件化,但颗粒度更大,用于组织应用
- 四大属性:imports、controllers、providers、exports
- 四种类型:功能模块、共享模块、全局模块、动态模块
- providers 理解:Service 层的容器,做脏活累活,实现依赖注入
- 最佳实践:按业务功能划分、高内聚低耦合、避免循环依赖
行动建议
code
学习路径:
│
├── 第一阶段:理解概念(1-2 天)
│ ├── 理解模块化和组件化的关系
│ ├── 理解 @Module 四大属性
│ └── 理解四种模块类型
│
├── 第二阶段:实践练习(1 周)
│ ├── 创建功能模块(用户、订单)
│ ├── 创建共享模块(日志、工具)
│ ├── 创建全局模块(数据库)
│ └── 创建动态模块(配置)
│
└── 第三阶段:项目应用(持续)
├── 设计合理的模块架构
├── 解决循环依赖问题
└── 优化模块组织结构十、延伸学习资源
官方资源
练习建议
- 练习 1:创建一个完整的功能模块(用户模块)
- 练习 2:创建共享模块,实现跨模块共享 Service
- 练习 3:创建全局模块,实现全局日志服务
- 练习 4:创建动态模块,实现数据库配置
- 练习 5:解决一个循环依赖问题
延伸思考
code
思考题:
│
├── 什么时候使用共享模块,什么时候使用全局模块?
├── 如何避免循环依赖?
├── 动态模块和普通模块的本质区别是什么?
├── 如何设计一个合理的模块架构?
└── providers 为什么不能导入模块?附录:模块化速查表
| 概念 | 说明 | 关键词 |
|---|---|---|
| 功能模块 | 按业务功能划分 | UsersModule、OrdersModule |
| 共享模块 | 跨模块共享功能 | SharedModule、exports |
| 全局模块 | 全局可用 | @Global()、无需导入 |
| 动态模块 | 按需初始化 | forRoot()、懒加载 |
| imports | 导入其他模块 | 导入后可用其 exports |
| exports | 导出供其他模块使用 | 被 import 后可用 |
| providers | 注册服务 | Service、Repository |
| controllers | 注册控制器 | 处理请求 |
笔记整理完成时间:2026-03-07
下一章节预告:NestJS 数据库集成实战