AspectJ入门(二)— 应用

 AspectJ便于调试、测试和性能调整工作。定义的行为范围从简单的跟踪到分析,再到应用程序内部一致性到测试。AspectJ可以干净地模块化这类功能,从而可以在需要时轻松地启用和禁用这些功能。

1 基础

本节将继续介绍AspectJ到一些基础功能,为后面的应用提供使用基础。

1.1 thisJoinPoint

当前连接点,提供对连接点可用状态及其静态信息的反射访问。

thisJoinPoint分为静态及实例部分。静态部分包含了连接点类型、签名及位置等信息。实例部分包含了连接点所在的this,代理对象及方法参数。

1.1.1 staticPart静态部分

可通过aspectJ变量:thisJoinPointStaticPart(如果只对连接点的静态信息感兴趣,则应通过访问此变量来以获得更佳性能) 或者thisJoinPoint.getStaticPart()获取静态部分。

图 连接点静态部分的方法

getId 方法获取的id是从0开始的。同一个切点下不同的连接点id是从0开始递增的。

图 静态部分代码及运行结果

1.1.2 实例部分的this 与 target

this: 连接点所在的this对象,当此对象不存在时返回空。(不包括静态空间及方法)。

target:目标对象,即代理对象。

我们可以通过连接点的实例来获取this、target及advice的参数。在实际开发中,我们通常不采用这种方式,因为这种方式会更耗时。我们可以通过下面的方式来获取这些参数:

public aspect ThisAndTargetAspect {

    after(ThisAndTarget.TestThisAndTarget obj, ThisAndTarget target, String inputStr) returning(String str):
            call(String article.custom.ThisAndTarget.fun1(String))
            && args(inputStr) && target(target) && this(obj){
        System.out.println("参数:" + inputStr);
        System.out.println("返回值:" + str);
        System.out.println("this:" + obj);
        System.out.println("target:" + target);
    }

}

1.2 切点的部分声明关键词

1.2.1 call 与 execution

call: 调用方法的地方。

execution:方法执行的地方。

图 call与execution的演示代码及运行结果

1.2.2 withincode

withincode 指定特定方法作用域内的所有连接点(不包括该方法里所调用方法的相关连接点)。而within则是指定类的所有连接点。

图 withincode 演示代码及运行结果

2 应用

AspectJ 可用于跟踪调试、日志记录及契约约束等场景。在开发中,我们可以通过一个配置文件来控制是否使用AspectJ,从而控制AspectJ模块的插拔。

2.1 跟踪调试

在调试代码过程中,我们需要写好多测试方法来测试某个类的函数,甚至有时需要在被测试的方法中插入些测试代码以获得某些结果值。在测试完后我们需要把这些代码删除。这样容易删除一些业务代码,同时也带来了一定的工作量。

业务上线时我们要把这些测试代码移除,但是有时我们希望保持它们以供下个版本的测试。

使用AspectJ让上面这些需求的实现变得更容易。

public class TestEntity {

    public int fun1(int num1, int num2) {
        if (num2 > 99) num2 = 0;
        return num1 + num2;
    }

    public static void main(String[] args) {
        TestEntity entity = new TestEntity();
        entity.fun1(3,99);
        entity.fun1(63,101);
    }

}


public aspect TestEntityAspect {

    after(int num1,int num2) returning(int sum): call(int article2.custom.TestEntity.fun1(int,int)) && args(num1,num2) {
        System.out.println(thisJoinPoint.getSignature() + "的测试");
        System.out.println("参数是num1:" + num1 + ";num2:" + num2);
        System.out.println("结果是:" + sum);
        int result = num1 + num2;
        System.out.println("预期结果:" + result);
        if (result != sum) {
            throw new RuntimeException(thisJoinPoint.getSignature() + "结果值不对");
        }
    }

}

2.2 日志记录

我们借助log4j等框架记录日志时,通常会在业务代码里插入记录日志的代码。这样让业务代码变得更加繁杂。同时,如果我们想在第三方库的方法中记录日志,平常方法将无法实现。

借助AspectJ我们可以很轻松的记录日志及对第三方库中的方法进行日志记录。

需求:统计LogEntity 的fun方法在fun1中被调用的次数(fun可能在其他方法中也会被调用)。

public class LogEntity {

    public void fun() {
        System.out.println("fun");
    }

    public void fun1() {
        fun();
        System.out.println("fun1");
        fun();
    }

    public void fun2() {
        fun();
        System.out.println("fun2");
        fun();
    }

    public static void main(String[] args) {
        LogEntity logEntity = new LogEntity();
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            int nextInt = random.nextInt(11);
            if (nextInt > 5) logEntity.fun1();
            else logEntity.fun2();
        }
    }

}

public aspect LogEntityAspect {

    private static int count = 0;

    after(): call(void article2.custom.LogEntity.fun()) && withincode(void article2.custom.LogEntity.fun1()) {
        count++;
        System.out.println("被调用次数:" + count);
    }

}

2.3 前置或后置条件

现在好多项目都采用“契约式设计”方法。Design By Contract,简称DbC。这种设计方法要求软件设计者为软件组件定义正式的,准确的并且可验证的接口。

契约式设计的三个部分:

1)前置条件:为了调用函数,必须为真的条件。在其违反时,函数绝不调用。

2)后置条件:函数完成时的状态。确保该状态符合预期结果。

3) 不变式:保证类的状态在任何功能被执行后都保持在一个可接受的状态。

AspectJ 可以很容易编写前置及后置条件。

public class ContractEntity {

    public double division(double num1, double num2) {
        if (num1 > 999) num1 = 0;
        return num1 / num2;
    }

    public static void main(String[] args) {
        ContractEntity entity = new ContractEntity();
        entity.division(34,2);
//        entity.division(42,0);
        entity.division(2134,34);
    }

}

public aspect ContractEntityAspect {

    before(double num1,double num2):call(double article2.custom.ContractEntity.division(double,double )) && args(num1,num2) {
        if (num2 == 0) {
            throw new RuntimeException("被除数不能为0");
        }
    }

    after(double num1,double num2) returning(double res):call(double article2.custom.ContractEntity.division(double,double )) && args(num1,num2){
        String str = "除数:" + num1 + ";被除数:" + num2;
        System.out.println(str);
        double num = num1 / num2;
        System.out.println("预期值:" + num);
        System.out.println("结果:" + res);
        if (num != res) {
            throw new RuntimeException("计算结果有误:" + str);
        }
    }

}

2.4 定义编译器错误

declare error: 切点表达式 : “错误提示”;  定义一个错误,会在代码编译器抛出。

declare error: call(* article.custom.DeclareEntity.fun1(..)): "不能使用该方法";

上面这条语句的含义是:如果在代码中有调用DeclareEntity的fun1方法,那么在编译代码时,将抛出错误“不能使用该方法”。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

负载均衡案例:如何只用2GB内存统计20亿个整数中出现次数最多的整数

基于python实现。 如果是常规的小型文件&#xff0c;我们可以迅速地想到要建立字典。 以数字为key&#xff0c;以数字的出现次数为value&#xff0c;建立<int,int>类型的键值对存入字典&#xff0c;然后使用 max 函数结合字典的 items 方法来找到一个字典中 value 最大的…

2023 波卡年度报告选读:Polkadot SDK 与开发者社区

原文&#xff1a;https://dashboards.data.paritytech.io/reports/2023/index.html#section6 编译&#xff1a;OneBlock 编者注&#xff1a;Parity 数据团队发布的 2023 年 Polkadot 年度数据报告&#xff0c;对推动生态系统的关键数据进行了深入分析。报告全文较长&#xff…

一键减低PNG像素,轻松优化图片质量!

在数字时代&#xff0c;我们每天都要处理大量的图片文件&#xff0c;从网站设计、广告素材到社交媒体图片等。PNG作为一种常用的无损压缩格式&#xff0c;在保证图片质量的同时&#xff0c;也占用了较大的存储空间。为了优化存储空间和提高加载速度&#xff0c;我们需要对PNG图…

数据结构学习笔记——查找算法中的树形查找(B树、B+树)

目录 前言一、B树&#xff08;一&#xff09;B树的概念&#xff08;二&#xff09;B树的性质&#xff08;三&#xff09;B树的高度&#xff08;四&#xff09;B树的查找&#xff08;五&#xff09;B树的插入&#xff08;六&#xff09;B树的删除 二、B树&#xff08;一&#xf…

科技助力教育:数字化如何改变家校社协同育人?

近年来,随着社会的快速发展,教育的责任已不再仅局限于学校。家庭、学校和社会协同育人理念,正成为促进教育高质量发展的关键要素。 2023年初,教育部等十三部门联合印发《关于健全学校家庭社会协同育人机制的意见》,提出到“十四五”时期末,形成更加完善的由“学校积极主导、家…

Excel如何将单元格设为文本

文章目录 一、打开excel文件二、选中单元格三、右键设置单元格格式四、设置界面选择文本后点确定五、其他问题 在caa开发过程中遇到从CATUnicodeString转成CString时&#xff0c;通过SetItemText写入将ID号写入单元格&#xff0c;无法保存ID号中的数字0&#xff0c;故将单元格格…

统信UOS_麒麟KYLINOS修改图标显示名称

原文链接&#xff1a;统信UOS/麒麟KYLINOS修改图标显示名称 hello&#xff0c;大家好啊&#xff01;今天我要给大家介绍的是在统信UOS及麒麟KYLINOS操作系统上如何修改软件的名称。这种自定义可以帮助您更快地识别和访问常用的应用程序&#xff0c;也可以使您的桌面环境更加个性…

【MATLAB】CEEMD_LSTM神经网络时序预测算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 CEEMD-LSTM神经网络时序预测算法是一种结合了完全扩展经验模态分解&#xff08;CEEMD&#xff09;和长短期记忆神经网络&#xff08;LSTM&#xff09;的时间序列预测方法。 CEEMD是一种改…

基于MyCat2.0实现MySQL分库分表方案

目录 一、MyCat概述 二、MyCat作用 2.1 数据分片 2.1.1 垂直拆分 2.1.1.1 垂直分库 2.1.1.2 垂直分表 2.1.1.3 总结 2.1.2 水平拆分 2.1.2.1 水平分库 2.1.2.2 水平分表 2.1.2.3 总结 2.2 读写分离 2.3 多数据源整合 三、MyCat 与ShardingJDBC的区别 3.1 MyCat …

易基因:ChIP-seq等揭示Runx2通过转录调控Itgav表达激活肝星状细胞以促进肝纤维化|科研进展

这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 肌成纤维细胞&#xff08;myofibroblasts&#xff09;主要由肝脏中活化的肝星状细胞(hepatic stellate cells HSC)组成&#xff0c;在肝纤维化进展中发挥着核心作用。由于肌成纤维细胞主要负责细胞外基质蛋…

代码随想录刷题第三十六天| 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

代码随想录刷题第三十六天 无重叠区间 (LC 435) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:intervals.sort(keylambda x: (x[0],x[1]))count 0right intervals[0][1]for i in ra…

拼题A 跨年挑战赛 2024 赛后提交入口 + 题目 + 题解

赛后也想提交&#xff1f;点击进入 拼题A教育超市 周三&#xff0c;搞学长&#xff1a;“小柳进前十了&#xff01;想要奖品过来拿&#xff01;” 等了好几天的比赛结果终于出来了&#xff0c;四年来的跨年挑战赛第一次做满分&#xff0c;第一次进前十&#xff01;&#xff0…

MyBatis学习二:Mapper代理开发、配置文件完成增删改查、注解开发

前言 公司要求没办法&#xff0c;前端也要了解一下后端知识&#xff0c;这里记录一下自己的学习 学习教程&#xff1a;黑马mybatis教程全套视频教程&#xff0c;2天Mybatis框架从入门到精通 文档&#xff1a; https://mybatis.net.cn/index.html Mapper代理开发 目的 解决…

【nginx】linux(centos版本)安装nginx

目录 一、下载安装包1.1 官网下载1.2 linux命令下载 二、安装2.1 安装依赖包2.2 安装nginx 三、启动四、访问五、关停六、重载配置 一、下载安装包 1.1 官网下载 1.官网地址 https://nginx.org/en/download.html2.版本说明 1.Mainline version-主线版本 2.Stable version-稳…

剪映业务的大前端实践:创新以用户需求为导向

近日&#xff0c;由51CTO主办的WOT全球技术创新大会2023深圳站成功举办&#xff0c;众多企业CTO、技术团队负责人在会场分享了优秀的技术实践。其中&#xff0c;剪映前端开发工程师赵培霏分享了主题为《剪映业务的大前端实践》的演讲。 近日&#xff0c;由51CTO主办的WOT全球技…

如何给6000微信好友打好标签? 快速操作技巧!

微信好友一多&#xff0c;管理起来就变得麻烦。要管理好好友&#xff0c;就必须要给好友打好标签。今天分享一个快速给微信好友打标签的方法。 一、微信电脑端给好友打标签的操作方法&#xff1a; 桌面端打标签速度是很快的&#xff0c;不仅仅是好操作&#xff0c;而且搜索功能…

Spark调优解析-GC调优3(七)

1 GC调优 Spark立足内存计算&#xff0c;常常需要在内存中存放大量数据&#xff0c;因此也更依赖JVM的垃圾回收机制。与此同时&#xff0c;它也兼容批处理和流式处理&#xff0c;对于程序吞吐量和延迟都有较高要求&#xff0c;因此GC参数的调优在Spark应用实践中显得尤为重要。…

2023 IoTDB Summit:清华大学软件学院长聘副教授龙明盛《IoTDB 新组件:内生机器学习》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…

Starknet 开发实战训练营邀你挑战,1000 美元大奖等你赢取!

Starknet 免费公开课来啦&#xff01;&#x1f680; ZK L2 明星项目 Starknet 不久前透露其 STRK 空投计划引发了诸多关注&#xff0c;而全链游戏同样是今年 Web3 行业的热门领域之一&#xff0c;Starknet 便是全链游戏领域中的重要生态&#xff0c;开发者借助其链上游戏引擎 D…

【驱动序列】C#获取电脑硬件基本组合以及基础信息

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读《小5讲堂之知识点实践序列》文章。 这是2024年第7篇文章&#xff0c;此篇文章是C#知识点实践序列文章&#xff0c;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 要开发一款驱动小助手&…