VonaJS AOP编程大杀器:外部切面

news/2025/10/27 9:52:31/文章来源:https://www.cnblogs.com/zhennann/p/19168031

在VonaJS框架中,AOP编程包括三方面:控制器切面内部切面外部切面

  1. 控制器切面: 为 Controller 方法切入逻辑,包括:Middleware、Guard、Interceptor、Pipe和Filter
  2. 内部切面: 在 Class 内部,为任何 Class 的任何方法切入逻辑,包括:AOP Method和魔术方法
  3. 外部切面: 在不改变 Class 源码的前提下,从外部为任何 Class 的任何方法切入逻辑

VonaJS中的外部切面,可以类比于Spring Boot中的AOP切面AOP织入概念。VonaJS的外部切面不需要什么前置通知后置通知异常通知环绕通知,只需提供一个同名方法就可以了。之所以可以这么简洁,是因为使用了洋葱圈模型。

此外,VonaJS的外部切面支持完整的类型推断与智能代码提示,开发体感比Spring Boot优雅太多。

下面,我们就来考察一下VonaJS的外部切面到底是个什么样?为什么可以成为AOP编程的🚀大杀器🔪

创建目标Class

可以针对任何 Class 实现外部切面。下面,以 Service 为例,在模块 demo-student 中创建一个 Service test,代码如下:

@Service()
export class ServiceTest extends BeanBase {private _name: string;protected __init__() {this._name = '';}protected async __dispose__() {this._name = '';}get name() {return this._name;}set name(value) {this._name = value;}actionSync(a: number, b: number) {return a + b;}async actionAsync(a: number, b: number) {return Promise.resolve(a + b);}
}

创建外部切面

接下来,创建一个外部切面log,为 Class ServiceTest的属性和方法分别提供扩展逻辑

1. Cli命令

$ vona :create:bean aop log --module=demo-student

2. 菜单命令

右键菜单 - [模块路径]: Vona Aspect/Aop

AOP定义

import { BeanAopBase } from 'vona';
import { Aop } from 'vona-module-a-aspect';@Aop({ match: 'demo-student.service.test' })
export class AopLog extends BeanAopBase {}
  • @Aop: 此装饰器用于实现外部切面
  • match: 用于将 Class AopLog与 Class ServiceTest关联,ServiceTest的 beanFullName 是demo-student.service.test
名称 类型 说明
match string|regexp|(string|regexp)[] 针对哪些 Class 启用

切面:同步方法

ServiceTest#actionSync输出运行时长

在 VSCode 编辑器中,输入代码片段aopactionsync,自动生成代码骨架:

action: AopAction<ClassSome, 'action'> = (_args, next, _receiver) => {return next();
};

调整代码,然后添加 log 逻辑

actionSync: AopAction<ServiceTest, 'actionSync'> = (_args, next, _receiver) => {const timeBegin = Date.now();const res = next();const timeEnd = Date.now();console.log('actionSync: ', timeEnd - timeBegin);return res;
};
  • actionSync: 提供与ServiceTest同名的方法actionSync

切面:异步方法

ServiceTest#actionAsync输出运行时长

在 VSCode 编辑器中,输入代码片段aopaction,自动生成代码骨架:

action: AopAction<ClassSome, 'action'> = async (_args, next, _receiver) => {return await next();
};

调整代码,然后添加 log 逻辑

actionAsync: AopAction<ServiceTest, 'actionAsync'> = async (_args, next, _receiver) => {const timeBegin = Date.now();const res = await next();const timeEnd = Date.now();console.log('actionAsync: ', timeEnd - timeBegin);return res;
};
  • actionAsync: 提供与ServiceTest同名的方法actionAsync

切面:getter

ServiceTest#get name输出运行时长

在 VSCode 编辑器中,输入代码片段aopgetter,自动生成代码骨架:

protected __get_xxx__: AopActionGetter<ClassSome, 'xxx'> = function (next, _receiver) {const value = next();return value;
};

调整代码,然后添加 log 逻辑

protected __get_name__: AopActionGetter<ServiceTest, 'name'> = function (next, _receiver) {const timeBegin = Date.now();const value = next();const timeEnd = Date.now();console.log('get name: ', timeEnd - timeBegin);return value;
};
  • __get_name__: 对应ServiceTest的 getter 方法get name

切面:setter

ServiceTest#set name输出运行时长

在 VSCode 编辑器中,输入代码片段aopsetter,自动生成代码骨架:

protected __set_xxx__: AopActionSetter<ClassSome, 'xxx'> = function (value, next, _receiver) {return next(value);
}

调整代码,然后添加 log 逻辑

protected __set_name__: AopActionSetter<ServiceTest, 'name'> = function (value, next, _receiver) {const timeBegin = Date.now();const res = next(value);const timeEnd = Date.now();console.log('set name: ', timeEnd - timeBegin);return res;
};
  • __set_name__: 对应ServiceTest的 setter 方法set name

切面:__init__

ServiceTest#__init__输出运行时长

在 VSCode 编辑器中,输入代码片段aopinit,自动生成代码骨架:

protected __init__: AopActionInit<ClassSome> = (_args, next, _receiver) => {next();
};

调整代码,然后添加 log 逻辑

protected __init__: AopActionInit<ServiceTest> = (_args, next, _receiver) => {const timeBegin = Date.now();next();const timeEnd = Date.now();console.log('__init__: ', timeEnd - timeBegin);
};
  • __init__: 提供与ServiceTest同名的方法__init__

切面:__dispose__

ServiceTest#__dispose__输出运行时长

在 VSCode 编辑器中,输入代码片段aopdispose,自动生成代码骨架:

protected __dispose__: AopActionDispose<ClassSome> = async (_args, next, _receiver) => {await next();
};

调整代码,然后添加 log 逻辑

protected __dispose__: AopActionDispose<ServiceTest> = async (_args, next, _receiver) => {const timeBegin = Date.now();await next();const timeEnd = Date.now();console.log('__dispose__: ', timeEnd - timeBegin);
};
  • __dispose__: 提供与ServiceTest同名的方法__dispose__

切面:__get__

ServiceTest扩展魔术方法

  • 参见: 魔术方法

在 VSCode 编辑器中,输入代码片段aopget,自动生成代码骨架:

protected __get__: AopActionGet<ClassSome> = (_prop, next, _receiver) => {const value = next();return value;
};

调整代码,然后添加自定义字段red

protected __get__: AopActionGet<ServiceTest> = (prop, next, _receiver) => {if (prop === 'red') return '#FF0000';const value = next();return value;
};
  • __get__: 约定的魔术方法名称

通过接口类型合并的机制为颜色提供类型定义

declare module 'vona-module-demo-student' {export interface ServiceTest {red: string;}
}

切面:__set__

ServiceTest扩展魔术方法

  • 参见: 魔术方法

在 VSCode 编辑器中,输入代码片段aopset,自动生成代码骨架:

protected __set__: AopActionSet<ClassSome> = (_prop, value, next, _receiver) => {return next(value);
};

调整代码,为自定义字段red设置值

private _colorRed: string | undefined;protected __set__: AopActionSet<ServiceTest> = (prop, value, next, _receiver) => {if (prop === 'red') {this._colorRed = value;return true;}return next(value);
};
  • __set__: 约定的魔术方法名称
  • 如果为prop设置了值,返回true,否则调用next方法

然后调整__get__的逻辑:

protected __get__: AopActionGet<ServiceTest> = (prop, next, _receiver) => {
- if (prop === 'red') return '#FF0000';
+ if (prop === 'red') return this._colorRed;const value = next();return value;
}

切面:__method__

ServiceTest的任何方法扩展逻辑

在 VSCode 编辑器中,输入代码片段aopmethod,自动生成代码骨架:

protected __method__: AopActionMethod<ClassSome> = (_method, _args, next, _receiver) => {return next();
};

调整代码,然后为方法actionSyncactionAsync添加 log 逻辑

protected __method__: AopActionMethod<ServiceTest> = (method, _args, next, _receiver) => {if (method !== 'actionSync' && method !== 'actionAsync') {return next();}const timeBegin = Date.now();function done(res) {const timeEnd = Date.now();console.log(`method ${method}: `, timeEnd - timeBegin);return res;}const res = next();if (res?.then) {return res.then((res: any) => {return done(res);});}return done(res);
};
  • __method__: 约定的魔术方法名称
  • res?.then: 判断返回值是否是 Promise 对象,进行不同处理,从而兼容同步方法异步方法

AOP顺序

针对同一个目标 Class,可以关联多个 AOP。所以,VonaJS 提供了两个参数,用于控制 AOP 的执行顺序

1. dependencies

比如,还有一个 AOP demo-student:log3,我们希望执行顺序如下:demo-student:log3 > Current

@Aop({match: 'demo-student.service.test',
+ dependencies: 'demo-student:log3',
})
class AopLog {}

2. dependents

dependents的顺序刚好与dependencies相反,我们希望执行顺序如下:Current > demo-student:log3

@Aop({match: 'demo-student.service.test',
+ dependents: 'demo-student:log3',
})
class AopLog {}

AOP启用/禁用

可以控制 AOP 的启用/禁用

1. Enable

src/backend/config/config/config.ts

// onions
config.onions = {aop: {'demo-student:log': {
+     enable: false,},},
};

2. Meta

可以让 AOP 在指定的运行环境生效

名称 类型 说明
flavor string|string[] 参见: 运行环境与Flavor
mode string|string[] 参见: 运行环境与Flavor
  • 举例
@Aop({
+ meta: {
+   flavor: 'normal',
+   mode: 'dev',
+ },
})
class AopLog {}

查看当前生效的AOP清单

可以直接在目标 Class action 中输出当前生效的 AOP 清单

class ServiceTest {protected async __dispose__() {
+   this.bean.onion.aop.inspect();this._name = '';}
  • this.bean.onion: 取得全局 Service 实例 onion
  • .aop: 取得与 AOP 相关的 Service 实例
  • .inspect: 输出当前生效的 AOP 清单

当方法被执行时,会自动在控制台输出当前生效的 AOP 清单,效果如下:

aop-1

资源

  • Github:https://github.com/vonajs/vona
  • 文档:https://vona.js.org/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/947275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年深圳股权分割律师权威推荐榜单:婚姻/子女抚养权/离婚房产专业律师团队精选

面对婚姻中复杂的股权分割,深圳的专业律师们正以法律智慧为当事人守护权益。 在深圳这座经济活跃的城市,离婚案件中的股权分割问题日益增多。据深圳市中级人民法院公开数据显示,2025年家事案件中涉及公司股权分割的…

2025 年最新推荐三维扫描仪厂家权威排行榜:聚焦行业优质品牌,精选助力用户精准选购

引言 当前 3D 数字化技术飞速发展,三维扫描仪在文博、医疗、工业、建筑等领域应用愈发广泛,成为推动各行业数字化转型的关键设备。但市场上厂家数量繁杂,产品质量参差不齐,部分产品存在精度不足、稳定性差等问题,…

选择电流探头时是看峰峰值还是最大值?

在电力电子、电机控制、新能源等领域的测试与分析中,电流探头是捕捉电流信号、洞察电路工作状态的关键工具。然而,许多初学者在面对电流波形数据时,常常会陷入一个困惑:“应该关注峰峰值还是最大值?”尽管二者都是…

agents-from-scratch

agents-from-scratch https://github.com/fanqingsong/agents-from-scratchAgents From ScratchThe repo is a guide to building agents from scratch. It builds up to an "ambient" agent that can manag…

基于Java+Springboot+Vue开发的婚恋交友网站管理系统源码+运行步骤

项目简介该项目是基于Java+Springboot+Vue开发的婚恋交友网站管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。…

kvm安装debian13之后启动报错

原创kvm安装debian13之后启动报错报错信息如下 “Booting from DVD/CD... Boot failed: Could not read from CDROM (code 0003) No bootable device.”解决办法编辑虚拟机的启动信息 永久解决(修改虚拟机配置): 编…

2025 年最新推荐!钢结构防火涂料厂家排行榜:膨胀型 / 非膨胀型 / 室内外 / 超薄型 / 厚型防火涂料精选

引言 随着建筑防火安全需求升级,防火涂料市场关注度持续攀升。为给采购方提供精准选择依据,中国消防协会联合建筑材料测试中心开展 2025 年度防火涂料品牌测评,本次测评覆盖全国 82 家主流企业,从产品性能、品牌实…

案例解析:养老服务标杆吉宝欣岳年借助纷享销客CRM实现数字化转型升级

在全球老龄化趋势加速的背景下,养老产业正迎来数字化转型的关键机遇。吉宝集团旗下高品质养老品牌欣岳年,凭借其国际化运营团队和前瞻性视野,率先引入纷享销客CRM 系统,打造构建了一套安全、高效、可管控的数字化销…

20232407 2025-2026-1 《网络与系统攻防技术》 实验三实验报告

1.实验内容 实践内容 (1)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免杀工具或技巧正确使用msf编码器,使用msfvenom生成如jar之类的其他文件veil,加壳工具使用C + shellcode编程(2)通过组合应用各种…

20232325 2025-2026-1 《网络与系统攻防技术》实验三实验报告

实验文档 1.实验内容 1.1 回答问题(1)杀软是如何检测出恶意代码的?通过特征码检测; 根据程序行为规律判断; 根据程序运行时的实际行为来判断。(2)免杀是做什么? 对恶意程序做各种处理,让它免除杀毒软件检测,…

centos7通过阿里云的镜像站安装最新的docker服务

原创centos7通过阿里云的镜像站安装最新的docker服务要通过阿里云的镜像站安装最新版本的 Docker 服务,你可以按照以下步骤操作:卸载旧版本的 Docker(如果已安装): sudo yum remove docker \docker-client \docke…

2025年计算机技术、数字媒体与传播国际学术会议(ICCDC 2025)

2025年计算机技术、数字媒体与传播国际学术会议(ICCDC 2025) 2025 International Conference on Computer Technology, Digital Media and Communication 在全球数字化转型加速的背景下,计算机技术、数字媒体与传播…

2025 年造粒机,混合造粒机厂家最新推荐,聚焦资质、案例、售后的优质机构深度解读

引言 随着工业原料制备行业的持续升级,造粒机及混合造粒机的市场需求日益增长,但其品质差异给企业选购带来极大挑战。为助力企业精准筛选优质设备,中国通用机械工业协会联合行业权威检测机构开展 2025 年度造粒机厂…

题解:uoj748 机器人表演

每步都很厉害的一个题。 题意:给出一个不一定匹配的括号序列,求其和任意给定长度 \(t\) 的合法括号序列合并后有多少种本质不同的串。\(n,t\le 300\)。 做法: 首先考虑判定怎么做,我假设有原串 \(s\),我如何判定一…

2025 年混合机,强力混合机厂家最新推荐,产能、专利、环保三维数据透视!

引言 在国家推动环保装备制造业高质量发展的政策导向下,混合机作为工业生产核心设备,其性能直接关系到企业降本增效与绿色转型成效。为破解市场选型难题,本次测评联合中国通用机械工业协会,基于产能输出、专利储备…

Java dubbo spring springboot中的spi机制

在 Java 生态中,SPI(Service Provider Interface) 是一种服务发现机制,允许框架或接口定义方通过配置文件指定接口的实现类,第三方可以通过实现接口并配置文件来扩展功能,实现 “接口与实现分离”。Dubbo、Sprin…

此乃同余最短路

P3403 跳楼机 不妨令\(x<y<z\) 设\(f_i\)的值为最小的满足\((ay+bz)\bmod x=i\)的\(ay+bz\),那么对于任意\(\leq h\)的\(f_i+bx\)全都满足条件。只要求出所有\(f_i(0\leq i<x)\)就可以计算出可拼出的所有数,…

2025年深圳离婚房产律师权威推荐榜单:婚姻/子女抚养权/股权分割专业团队精选

在深圳这座快节奏的都市中,离婚案件涉及房产分割、子女抚养权及股权纠纷时,专业律师的帮助至关重要。根据2024年深圳市司法数据统计,离婚案件中房产分割争议占比高达60%以上,而专业婚姻家事律师的介入,能显著提升…

2025年深圳婚姻律师权威推荐榜单:离婚房产/子女抚养权/股权分割专业团队精选

在深圳这座快节奏的都市中,婚姻家事案件逐年增多,涉及离婚房产分割、子女抚养权争议及股权分割等复杂问题。数据显示,2024年深圳市法院受理的婚姻家事类案件超过5000件,其中约60%涉及财产分割纠纷,凸显了专业律师…

微软+清北联合突破:Reinforcement Pre-Training正在改写大模型训练规则

原文:https://mp.weixin.qq.com/s/3IuCBezsMVaSn8MnbmqwVQ 全文摘要该研究里提出了强化预训练(RPT),它是大语言模型和强化学习(RL)的一种全新扩展范式。简单说,就是把 “预测下一个 token” 改成了用强化学习训练…