Nest.js 的模块系统是其架构的核心组成部分,它借鉴了 Angular 的模块设计思想,通过模块化的方式组织代码,实现关注点分离、依赖管理和代码复用。模块系统让大型应用的结构更加清晰,便于维护和扩展。
一、模块的核心概念与作用
- 关注点分离
将相关功能(如用户管理、认证、日志等)封装到独立模块中,避免代码耦合。 - 依赖管理
明确模块间的依赖关系,通过导入(imports)和导出(exports)控制功能共享。 - 依赖注入作用域
模块定义了 provider 的作用域,确保服务在模块内高效共享。 - 代码组织
模块系统帮助团队按照功能域组织代码,提升项目可维护性。
二、模块的基本结构与创建
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 {}
三、模块的核心属性详解
- imports:模块依赖导入
当模块需要使用其他模块的功能时,通过imports
导入目标模块。例如:
kotlin
@Module({
imports: [AuthModule, DatabaseModule], // 导入多个模块
})
export class UserModule {}
- exports:功能导出
通过exports
声明模块内可被其他模块使用的 providers 或导入的模块:
less
@Module({
imports: [DatabaseModule],
providers: [UserService],
exports: [UserService, DatabaseModule], // 导出自身服务和导入的模块
})
export class UserModule {}
- providers:模块内服务注册
providers
包含模块所需的所有依赖注入对象(服务、仓库、工厂等),这些对象会在模块内共享:
less
@Module({
providers: [
UserService,
{
provide: 'USER_REPOSITORY',
useClass: UserRepository,
},
],
})
export class UserModule {}
- controllers:控制器注册
controllers
声明模块关联的控制器,控制器会接收请求并调用模块内的服务:
kotlin
@Module({
controllers: [UserController, AdminController],
})
export class UserModule {}
controllers
与providers
最大的不同是,每次请求都会创建一个controllers
,而providers
是单例模式,全局唯一。
四、模块间的依赖与共享
- 模块导入与功能共享
当模块 A 导入模块 B 后,模块 A 可以使用模块 B 导出的所有功能:
kotlin
// app.module.ts
@Module({
imports: [UserModule, AuthModule], // 导入用户模块和认证模块
})
export class AppModule {}
- 循环依赖处理
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)
动态模块允许在运行时配置模块,常用于需要动态参数的服务(如数据库连接、第三方服务集成)。通过 forRoot
和 forFeature
方法实现:
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 {}