什么是 AOP?
- AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式
- 它旨在通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来
- 实现模块化和可维护性
- 核心思想是:在不破坏原有封装的前提下,对系统功能进行非侵入式的功能增强
- 举个例子:
- 我们有一个业务系统 A,它本身具有自己的独立功能
- 如果我们现在要为系统 A 增加一个新功能(例如统一日志记录、权限控制、错误处理等)
- 我们不需要修改原有业务类,而是在业务之外通过 AOP 的方式
- 将这些新功能“织入”到目标业务流程中
AOP 与 OOP 的区别与互补
- 在 OOP(Object-Oriented Programming,面向对象编程)中
- 我们通过类(class)来组织业务逻辑
- 每个业务功能都封装在相应的对象中
当我们需要为多个类添加相同的功能时,通常的做法是:
- 继承:创建一个父类,让其他类继承它。
- 装饰器模式:通过包装类来扩展功能。
- 复制粘贴:在每个类中手动添加相同逻辑。
- 这些做法容易造成代码冗余、难以维护、违反开闭原则等问题
而 AOP 的出现正是为了解决这种问题。它允许我们:
- 将通用功能(如日志、事务、安全等)集中管理
- 在不修改原代码的前提下,横向插入到多个类的方法中
- 实现功能的复用与集中控制
AOP 是对 OOP 的补充,它弥补了 OOP 在横切关注点上的不足
AOP 的典型应用场景
这些功能通常会横跨多个模块或类,如果直接写在业务逻辑中,会导致代码冗余、逻辑混乱。而 AOP 可以让我们将这些功能集中定义,动态织入到需要的地方。
四、AOP 核心概念解析
Aspect(切面) | 是一个类,包含多个通知(Advice),用于定义要插入的横切功能 |
Join Point(连接点) | 程序执行过程中的某个特定点,比如方法调用前、调用后、抛异常等 |
Pointcut(切入点) | 定义哪些连接点会被切面处理,通常通过表达式匹配方法名 |
Advice(通知) | 切面在特定连接点上执行的动作,如前置通知、后置通知、异常通知等 |
Target Object(目标对象) | 被代理的对象,也就是原始业务对象 |
Weaving(织入) | 将切面代码插入到目标对象的过程,可以在编译时、类加载时或运行时完成 |
AOP 的优势总结
NestJS AOP 实现示例:日志拦截器
以下是 NestJS 相关实现的版本,结合 AOP 思想与 NestJS 框架特性(基于拦截器、装饰器等机制)
1 ) NestJS AOP 实现示例:日志拦截器
// 1. 定义日志拦截器(Logging Interceptor) – 核心切面逻辑
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const methodName = context.getHandler().name; // 获取当前调用的方法名
const className = context.getClass().name; // 获取当前控制器类名
// 【前置通知】方法调用前记录日志
console.log(`[AOP] 请求 ${className}.${methodName} 开始 | 参数: ${JSON.stringify(request.body)}`);
return next.handle().pipe(
tap(() => {
// 【后置通知】方法调用后记录日志
console.log(`[AOP] 请求 ${className}.${methodName} 完成`);
})
);
}
}
2 ) 业务服务层(Service) – 原始业务逻辑
// order.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class OrderService {
createOrder(orderData: any): string {
console.log('业务逻辑:创建订单中…');
return `订单 ${orderData.id} 创建成功`;
}
deleteOrder(id: string): string {
console.log('业务逻辑:删除订单中…');
return `订单 ${id} 已删除`;
}
}
3 ) 控制器层(Controller) – 接入切面
// order.controller.ts
import { Controller, Post, Delete, UseInterceptors, Body, Param } from '@nestjs/common';
import { OrderService } from './order.service';
import { LoggingInterceptor } from './logging.interceptor';
@Controller('orders')
@UseInterceptors(LoggingInterceptor) // 应用日志拦截器(切面)
export class OrderController {
constructor(private readonly orderService: OrderService) {}
@Post()
createOrder(@Body() orderData: any) {
return this.orderService.createOrder(orderData);
}
@Delete(':id')
deleteOrder(@Param('id') id: string) {
return this.orderService.deleteOrder(id);
}
}
// app.module.ts
import { Module } from '@nestjs/common';
import { OrderController } from './order.controller';
import { OrderService } from './order.service';
import { LoggingInterceptor } from './logging.interceptor';
@Module({
controllers: [OrderController],
providers: [
OrderService,
{
provide: APP_INTERCEPTOR, // 全局注册拦截器
useClass: LoggingInterceptor,
},
],
})
export class AppModule {}
执行效果演示,请求示例
POST /orders Body: { "id": "123", "product": "Laptop" }
控制台输出
[AOP] 请求 OrderController.createOrder 开始 | 参数: {"id":"123","product":"Laptop"}
业务逻辑:创建订单中…
[AOP] 请求 OrderController.createOrder 完成
关键设计解析
- 通过 @UseInterceptors() 装饰器动态织入日志功能,无需修改 OrderService 业务代码
- 拦截器(Interceptor):实现 NestInterceptor,在方法执行前后插入逻辑(类比 @Before/@After)
- 管道(Pipe):用于参数校验/转换(如 @Body() 数据清洗)。
- 守卫(Guard):处理权限控制(如 JWT 验证)
- ExecutionContext 提供请求方法、类、参数等元数据,实现精准日志记录 [6]。
- 局部:通过控制器/方法级 @UseInterceptors() 应用
- 全局:通过 APP_INTERCEPTOR 在模块中注册
对比传统 OOP 的优势
直接修改 Service | 高 (每个方法添加日志) | 高 | 低 |
NestJS AOP | 零重复 | 低 | 高 |
通过 AOP 将横切关注点(日志、权限等)与业务逻辑解耦 符合 “开放-封闭原则”(对扩展开放,对修改封闭)
扩展场景示例
权限守卫(Guard)
// auth.guard.ts
import { CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return validateToken(request.headers.authorization); // 权限验证逻辑
}
}
// 在控制器中使用
@UseGuards(AuthGuard)
@Delete(':id')
deleteOrder(@Param('id') id: string) { … }
异常过滤器(Exception Filter)
// http-exception.filter.ts
import { ExceptionFilter, Catch } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(500).json({ error: '统一错误处理' });
}
}
NestJS 的 AOP 实现层次
通过组合这些机制,NestJS 实现了 完整的 AOP 编程模型,显著提升代码复用性与可维护性
评论前必须登录!
注册