3. NestJS框架基础:模块、控制器、服务、依赖注入与装饰器模式
NestJS 是构建高效、可扩展 Node.js 服务端应用的首选框架。它通过结合 面向对象编程(OOP)、函数式编程(FP) 和 函数式响应式编程(FRP) 的思想,为开发者提供了类似 Spring 框架的模块化架构。本章将深入剖析 NestJS 的五大核心构造块:模块、控制器、服务、依赖注入与装饰器模式,为后续实现领域驱动设计与限流熔断的协同奠定坚实基础。
3.1 核心构造块总览
NestJS 应用由多个模块(Module)组成,每个模块封装了相关的控制器(Controller)、服务(Provider)和领域逻辑。下图展示了 NestJS 应用的基本分层与组件协作关系:
3.2 模块(Module)—— 组织的原子单位
模块是 NestJS 组织代码的基本单元,使用 @Module() 装饰器标记。每个模块负责声明其内部的控制器、服务以及需要导入的其他模块。
3.2.1 模块的核心属性
| 属性 | 作用 | 典型值 |
|---|---|---|
controllers |
注册该模块下的控制器实例 | [OrderController] |
providers |
注册可被注入的服务、工厂、仓库等 | [OrderService, PaymentGateway] |
imports |
导入其他模块,共享其导出的 providers | [DatabaseModule, LoggerModule] |
exports |
将本模块的部分 providers 暴露给其他模块 | [OrderService] |
// 订单模块示例
import { Module } from '@nestjs/common';
import { OrderController } from './order.controller';
import { OrderService } from './order.service';
import { PaymentModule } from '../payment/payment.module';
@Module({
imports: [PaymentModule], // 导入支付模块
controllers: [OrderController], // 注册控制器
providers: [OrderService], // 注册服务
exports: [OrderService], // 导出服务供其他模块使用
})
export class OrderModule {}
imports 和 exports 机制,恰好实现了上下文之间的依赖关系与防腐层(Anti-Corruption Layer)的集成点。
3.3 控制器(Controller)—— 请求入口与路由
控制器负责处理传入的 HTTP 请求并返回响应。它通过装饰器定义路由、请求方法和参数绑定,不包含任何业务逻辑。
3.3.1 控制器核心装饰器
| 装饰器 | 用途 | 示例 |
|---|---|---|
@Controller('path') |
定义控制器及基础路由前缀 | @Controller('orders') |
@Get() |
处理 GET 请求 | @Get(':id') |
@Post() |
处理 POST 请求 | @Post() |
@Body() |
提取请求体 | @Body() createDto: CreateOrderDto |
@Param() |
提取路由参数 | @Param('id') id: string |
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { OrderService } from './order.service';
import { CreateOrderDto } from './dto/create-order.dto';
@Controller('orders')
export class OrderController {
constructor(private readonly orderService: OrderService) {}
@Post()
async create(@Body() createDto: CreateOrderDto) {
return this.orderService.createOrder(createDto);
}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.orderService.getOrderById(id);
}
}
3.4 服务(Provider)—— 业务逻辑的载体
在 NestJS 中,几乎所有可被注入的类都可以称为 Provider,其中最典型的是 Service。服务使用 @Injectable() 装饰器标记,由 NestJS 的依赖注入容器管理其生命周期。
3.4.1 服务的注册方式
除了标准类注册,NestJS 还支持多种 Provider 注册模式,以适应不同的场景需求:
| 注册方式 | 适用场景 | 示例 |
|---|---|---|
| 标准类 | 大多数业务服务 | providers: [OrderService] |
| 值提供者 | 注入常量或配置对象 | { provide: 'CONFIG', useValue: config } |
| 工厂提供者 | 需要动态创建或异步初始化 | { provide: 'DB', useFactory: () => createDb() } |
| 别名提供者 | 为现有 provider 创建别名 | { provide: 'AliasService', useExisting: OrderService } |
import { Injectable } from '@nestjs/common';
@Injectable()
export class OrderService {
private orders: Map<string, any> = new Map();
createOrder(dto: CreateOrderDto) {
const order = { id: Date.now().toString(), ...dto, status: 'PENDING' };
this.orders.set(order.id, order);
return order;
}
getOrderById(id: string) {
return this.orders.get(id);
}
}
3.5 依赖注入(DI)—— 解耦的核心机制
依赖注入是 NestJS 实现控制反转(IoC)的核心手段。它允许开发者声明依赖关系,而无需手动管理对象的创建和生命周期。
3.5.1 DI 的工作流程
- 注册: 在模块的
providers中注册服务类。 - 声明: 在构造函数中通过类型声明依赖(如
constructor(private svc: OrderService))。 - 解析: NestJS 的 DI 容器自动查找并实例化所有依赖,递归处理依赖链。
- 注入: 将解析好的实例注入到目标类的构造函数中。
// DI 容器自动处理依赖链
@Injectable()
export class PaymentService {
constructor(private readonly httpService: HttpService) {} // 注入 HttpService
}
@Module({
providers: [PaymentService, HttpService], // 注册所有依赖
})
export class PaymentModule {}
DEFAULT(单例,整个应用共享)、REQUEST(每个请求创建新实例)、TRANSIENT(每次注入创建新实例)。在限流熔断场景中,通常使用 DEFAULT 作用域来维护全局的熔断器状态。
3.6 装饰器模式——NestJS 的语法基石
装饰器模式是 NestJS 框架的底层设计模式。它允许在不修改类本身的情况下,动态地为类、方法、属性或参数添加元数据和行为。
3.6.1 装饰器分类与用途
| 装饰器类型 | NestJS 示例 | 作用 |
|---|---|---|
| 类装饰器 | @Module(), @Controller(), @Injectable() |
标记类为特定构造块,附加元数据 |
| 方法装饰器 | @Get(), @Post(), @UseGuards() |
定义路由、HTTP 方法、守卫、拦截器 |
| 参数装饰器 | @Body(), @Param(), @Query() |
提取请求中的特定数据 |
| 属性装饰器 | @Inject() |
显式指定注入的 token |
3.6.2 自定义装饰器实战
在限流熔断场景中,我们可以创建自定义装饰器来简化限流逻辑的注入:
import { SetMetadata } from '@nestjs/common';
// 定义限流元数据 key
export const RATE_LIMIT_KEY = 'rate_limit';
// 创建自定义装饰器
export const RateLimit = (limit: number, ttl: number) =>
SetMetadata(RATE_LIMIT_KEY, { limit, ttl });
// 在控制器中使用
@Controller('orders')
export class OrderController {
@Post()
@RateLimit(10, 60) // 60 秒内最多 10 次请求
async create(@Body() dto: CreateOrderDto) {
// ...
}
}
3.7 本章小结
NestJS 的模块、控制器、服务、依赖注入与装饰器模式共同构成了一个高度解耦、可测试的架构体系:
- 模块 作为领域边界,组织相关功能并管理依赖关系。
- 控制器 作为 HTTP 适配器,处理输入输出转换。
- 服务 承载核心业务逻辑,通过 DI 实现松耦合。
- 依赖注入 自动管理对象生命周期,提升可测试性。
- 装饰器模式 提供声明式元数据编程能力,是框架扩展性的基石。