AOP编程有三大场景:控制器切面,内部切面,外部切面,你get到了吗?

如果用过NestJS框架都知道,在NestJS框架中AOP编程包括以下几个能力:Middleware、Guard、Interceptor、Pipe、Filter。事实上AOP编程的应用场景更广泛,上述所列5个能力仅仅是AOP编程的子集。下面,我们看看在VonaJS框架中,AOP编程是怎样的。

VonaJS AOP编程

VonaJS AOP 编程包括三个方面的能力:

  1. 控制器切面: 为 Controller 方法切入逻辑
  2. 内部切面: 在 Class 内部,为任何 Class 的任何方法切入逻辑
  3. 外部切面: 在不改变 Class 源码的前提下,从外部为任何 Class 的任何方法切入逻辑

控制器切面

控制器切面清单

  • Middleware
  • Guard
  • Intercepter
  • Pipe
  • Filter

执行时序图

控制器切面的执行时序图如下:

  • 洋葱模型: MiddlewareIntercepter支持洋葱模型,允许在Controller Action之前和之后执行切面逻辑
  • Middleware: 针对不同的执行时序节点,系统提供了三种 Middleware: Middleware SystemMiddleware GlobalMiddleware Local,从而可以实现更精细化的切面逻辑
  • Route Match: 只有Middleware System在路由匹配之前执行,其余在路由匹配之后执行
  • Filter: 任何环节抛出异常,都会执行Filter,从而自定义错误信息错误日志的处理逻辑

内部切面

内部切面提供两个机制:AOP Method魔术方法

1. AOP Method

直接在 Class Method 上通过装饰器切入逻辑

举例:数据库事务

diff 复制代码
class ServiceStudent {
+ @Database.transaction()
  async update(id: TableIdentity, student: DtoStudentUpdate) {
    return await this.scope.model.student.updateById(id, student);
  }
}
  • @Database.transaction:通过AOP Method机制实现的装饰器,可以直接提供数据库事务能力

举例:日志

diff 复制代码
class ServiceStudent {
+ @Log()
  async update(id: TableIdentity, student: DtoStudentUpdate) {
    return await this.scope.model.student.updateById(id, student);
  }
}
  • @Log:通过AOP Method机制实现的装饰器,可以直接提供日志能力

2. 魔术方法

可以在 Class 内部通过__get____set__切入动态属性或方法

举例:获取 model 实例

diff 复制代码
class ServiceStudent {
  async update(id: TableIdentity, student: DtoStudentUpdate) {
+   return await this.scope.model.student.updateById(id, student);
  }
}
  • this.scope.model.xxx: 没有使用依赖注入,而是使用依赖查找,直接通过 scope 对象获取 model 实例,从而简化代码的书写风格

实现思路

系统提供了一个 Class ServiceModelResolver,用于实现 model 实例的动态解析,代码如下:

typescript 复制代码
class ServiceModelResolver {
  protected __get__(prop: string) {
    const beanFullName = `${this[SymbolModuleScope]}.model.${prop}`;
    return this.bean._getBean(beanFullName as any);
  }
}
  1. 当调用this.scope.model.student时,会自动执行__get__方法,并且传入参数prop: 'student'
  2. 将参数prop与当前模块名称合并成beanFullName
  3. 通过beanFullName从全局容器中获取 model 实例,并返回给调用者

外部切面

仍以 Class ServiceStudentupdate方法为例,通过外部切面来实现日志能力:

typescript 复制代码
import { Aop } from 'vona-module-a-aspect';

@Aop({ match: 'demo-student.service.student' })
class AopLog {
  async update(_args: Parameters<any>, next: Function, _receiver: any) {
    const timeBegin = Date.now();
    const res = await next();
    const timeEnd = Date.now();
    console.log('time: ', timeEnd - timeBegin);
    return res;
  }
}
  • @Aop: 此装饰器用于实现外部切面
  • match: 用于将 Class AopLog与 Class ServiceStudent关联,ServiceStudent的 beanFullName 是demo-student.service.student
  • update: 在AopLog中提供与ServiceStudent同名的方法update,实现自定义逻辑即可

资源

相关推荐
Wang's Blog12 小时前
Nestjs框架: 微服务容器化部署与网络通信解决方案
docker·微服务·云原生·架构·nestjs
那年窗外下的雪.13 小时前
鸿蒙ArkUI布局与样式进阶(十五)—— 模块化 · 自定义组件 · 泛型机制深度解析
javascript·华为·typescript·harmonyos·鸿蒙·arkui
showmethetime13 小时前
使用 Node.js 和 Express 构建 RESTful API
node.js·restful·express
guangzan16 小时前
React 状态管理的“碎片化”
typescript·zustand
老友@19 小时前
Docker 部署 Node.js + Playwright 项目,实现浏览器截图、打印和下载
docker·容器·node.js·playwright
前端摸鱼匠1 天前
Vue 3 事件修饰符全解析:从 .stop 到 .passive,彻底掌握前端交互的艺术
前端·vue.js·node.js·vue·交互
小琴爱减肥1 天前
nodejs 文件系统(fs)
node.js
岁月宁静1 天前
图像生成接口的工程化设计与落地实践:封装豆包图像生成模型 Seedream 4.0 API
前端·人工智能·node.js
慢知行1 天前
从 0 到 1 搭建 Vite+Vue3+TS 工程模板:能上手操作的指南
前端·vue.js·typescript