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方法,那么在编译代码时,将抛出错误“不能使用该方法”。

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

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

相关文章

水稻潜在产量估算解决方案

1.背景与技术路线 统计资料表明&#xff0c;尽管我国粮食单产已由 50 年代初期的 1.2t/ha 增加到如今的 5.2t/h&#xff0c;粮食产量增加了 4 倍&#xff0c;但我国人口的增长速度与气候变化导致的农业生产的不确定性&#xff0c; 在水稻收获指数保持稳定的情况下&#xff0c;…

drf知识--10

接口文档 # 后端把接口写好后&#xff1a; 登录接口&#xff1a;/api/v1/login ---> post---name pwd 注册接口 查询所有图书带过滤接口 # 前后端需要做对接&#xff0c;对接第一个东西就是这个接口文档&#xff0c;前端照着接口文档开发 公司3个人&#xff…

Nginx 的SSL证书配置

目录 1.申请域名&#xff0c;证书下载 2.准备站点源代码 3.修改nginx 对应网站的配置文件 4.修改 host 文件 http协议访问的网站默认会显示不安全&#xff0c;因为数据默认是明文传输的 https是httpssl&#xff0c;ssl是加密协议&#xff0c;通过证书来进行加密的&#xff…

pod进阶:

pod进阶: 探针* poststart prestop pod的生命周期:pod的状态 k8s的重启策略 Always deployment的yaml文件只能是Always pod的yaml三种模式都可以。不论正常退场还是非正常退出都重启 OnFailure:只有状态码非0才会重启&#xff0c;正常退出是不重启的 Never: 正常退出和…

UG装配-引用集

引用集是控制组件的图素在装配体中显示与隐藏 装配体体环境控制组件显示与隐藏的四种方式 1、图层 2、引用集 3、隐藏命令 Ctrl B 4、抑制&#xff0c;取消此组件装配&#xff0c;但保留操作在导航器方便启用 引用集有两种类型 1、UG自动创建的引用集 2、用户定义的引…

Java 泛型深入解析

Java 中的泛型是一种强大的编程特性&#xff0c;允许我们编写更加通用和类型安全的代码。本篇博客将深入探讨 Java 泛型的各个方面&#xff0c;包括泛型类、泛型方法、泛型接口以及泛型通配符。 1. 泛型类 首先&#xff0c;让我们看一个简单的泛型类的例子。在下面的代码中&a…

Spring中的ApplicationContext和BeanFactory的区别??

ApplicationContext&#xff1a;只要一读取配置文件&#xff0c;默认情况下就会创建对象。 UserServiceImpl&#xff1a; package com.by.service;import com.by.dao.UserDao;/*** 业务层实现类*/ public class UserServiceImpl implements UserService {private UserDao user…

Flink 维表关联方案

Flink 维表关联方案 1、Flink DataStream 关联维表 1&#xff09;概述 1.分类 实时数据库查找关联&#xff08;Per-Record Reference Data Lookup&#xff09; 预加载维表关联&#xff08;Pre-Loading of Reference Data&#xff09; 维表变更日志关联&#xff08;Refere…

源头厂家定制直线度测量仪 在线与离线检测均可

直线度的检测不再局限于直尺法、重力法等人工检测方式&#xff0c;随着自动化的发展&#xff0c;直线度检测也更需要自动化方便快捷的检测仪器。为此&#xff0c;研发了在线直线度测量仪与离线直线度测量仪&#xff0c;根据不同的需要&#xff0c;选择合适的设备即可。 数据计…

轻量检测模型PP-PicoDet解析

Paper&#xff1a;PP-PicoDet: A Better Real-Time Object Detector on Mobile Devices official implementation&#xff1a;https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.7/configs/picodet Backbone 作者通过实验发现&#xff0c;ShuffleNetV2在移动…

NeRF-RPN: A general framework for object detection in NeRFs 全文翻译

摘要 Abstract 本文提出了第一个重要的物体检测框架 NeRF-RPN&#xff0c;它直接在 NeRF 上运行。给定一个预先训练好的 NeRF 模型&#xff0c;NeRF-RPN 的目标是检测场景中所有物体的边界框。通过利用包含多尺度三维神经体积特征的新颖体素表示法&#xff0c;我们证明…

ubuntu环境安装配置nginx流程

今天分享ubuntu环境安装配置nginx流程 一、下载安装 1、检查是否已经安装 nginx -v 结果 2、安装 apt install nginx-core 过程 查看版本&#xff1a;nginx -v 安装路径&#xff1a;whereis nginx nginx文件安装完成之后的文件位置&#xff1a; /usr/sbin/nginx&#xf…

Axure鲜花商城网站原型图,网上花店订花O2O本地生活电商平台

作品概况 页面数量&#xff1a;共 30 页 兼容软件&#xff1a;仅支持Axure RP 9/10&#xff0c;非程序软件无源代码 应用领域&#xff1a;鲜花网、花店网站、本地生活电商 作品特色 本作品为「鲜花购物商城」网站模板&#xff0c;高保真高交互&#xff0c;属于O2O本地生活电…

OpenVINS学习5——VioManager.cpp/h学习与注释

前言 之前又看到说VioManager.cpp/h是OpenVINS中的核心程序&#xff0c;这次就看看这里面都写了啥&#xff0c;整体架构什么样&#xff0c;有哪些函数功能。具体介绍&#xff1a; VioManager类 整体分析 VioManager类包含 MSCKF 工作所需的状态和其他算法。我们将测量结果输…

python的课后练习总结3之条件语句

1,简单点&#xff0c;只有IF IF 后面加入条件然后冒号: 条件成立执行的代码1 条件成立执行的代码2 条件是否成立都执行的代码 身高 float(input(请输入你的身高(米):)) if 身高 > 1.3:print(f您的身高是{身高}米,请您买票) print(祝您旅途愉快) 2,IF 加个else if 条件:…

Spring AOP的环境搭建、切入点表达式、通知注解

Spring AOP的实现 Spring AOP环境搭建AOP坐标依赖引入添加xml配置实现三层架构 定义切入点Pointcut("匹配规则")切入点表达式1. 执行所有的公共方法2.执行任意的set方法3.设置指定包下的任意类的任意方法 (指定包: com.svt.service)4.设置指定包及于包下的任意类的任…

用 Python 抓取 bilibili 弹幕并分析!

01 实现思路 首先&#xff0c;利用哔哩哔哩的弹幕接口&#xff0c;把数据保存到本地。接着&#xff0c;对数据进行分词。最后&#xff0c;做了评论的可视化。 02 弹幕数据 平常我们在看视频时&#xff0c;弹幕是出现在视频上的。实际上在网页中&#xff0c;弹幕是被隐藏在源代码…

【熔断限流组件resilience4j和hystrix】

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容起因resilience4j落地实现pom.xml依赖application.yml配置接口使用 hystrix 落地实现pom.xml依赖启动类上添加注解接口上使用 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟…

【期末复习向】数据可视化技术

一、重点复习 题型&#xff1a;填空题&#xff08;15道&#xff0c;2分一个&#xff09;与简答题&#xff08;3道题目&#xff0c;10分一个&#xff09;与绘图题&#xff08;选画2个类型的图&#xff09; 1.什么是数据可视化 在计算机视觉领域&#xff0c;数据可视化是对数据的…

Linux 进程(八) 进程的退出码

main 函数的返回值叫做进程的退出码。当进程成功退出的时候&#xff0c;我们一般用0来表示。进程失败的时候一般用非零来表示。我们使用不同的数字来表示进程退出时不同的失败原因。 我们查看系统的有多少退出码以及其含义时需要用到strerror() 他的头文件和用法如下。 通过一…