带有AOP和注释的Java方法记录

有时,我想记录(通过slf4j和log4j )方法的每次执行,查看其接收的参数,返回的内容以及每次执行需要多少时间。 这是我在AspectJ , jcabi-aspects和Java 6注释的帮助下进行的操作:

public class Foo {@Loggablepublic int power(int x, int p) {return Math.pow(x, p);}
}

这是我在log4j输出中看到的:

[INFO] com.example.Foo #power(2, 10): 1024 in 12μs
[INFO] com.example.Foo #power(3, 3): 27 in 4μs

很好,不是吗? 现在,让我们看看它是如何工作的。

带有运行时保留的注释

注释是Java 6中引入的一种技术。它是一种元编程工具,它不会改变代码的工作方式,但会为某些元素(方法,类或变量)提供标记。 换句话说,注释只是附加到可以查看和阅读的代码的标记。 某些注释仅在编译时可见-编译后在.class文件中不存在。 其他的在编译后仍然可见,并且可以在运行时访问。

例如, @Override是第一种类型(其保留类型是SOURCE ),而来自JUnit的@Test是第二种类型(保留类型是RUNTIME )。 @Loggable (我在上面的脚本中使用的那个)是jcabi-aspects中第二种类型的注释。 编译后,它与.class文件中的字节码保持在一起。

再次强调,重要的是要理解,即使方法power()已注释和编译,它到目前为止也不会向slf4j发送任何内容。 它只包含一个标记,上面写着“请记录我的执行情况”。

面向方面的编程(AOP)

AOP是一种有用的技术,它允许在不显式更改源代码的情况下将可执行块添加到源代码。 在我们的示例中,我们不想在类内部记录方法执行。 相反,我们希望其他类拦截对方法power()每次调用,测量其执行时间,然后将此信息发送给slf4j。

我们希望拦截器理解我们的@Loggable批注并记录对该特定方法power()每次调用。 而且,当然,其他的方法应使用相同的拦截器,以后我们将在其中放置相同的注释。

这种情况完全符合AOP的初衷-避免在多个类中重新实现某些常见行为。

日志记录是我们主要功能的补充功能,我们不想使用多个日志记录指令来污染我们的代码。 相反,我们希望在后台进行日志记录。

就AOP而言,我们的解决方案可以解释为创建一个方面 ,该方面在某些连接点横切代码,并应用环绕建议以实现所需的功能。

AspectJ

让我们看看这些神奇的词是什么意思。 但是,首先,让我们看一下jcabi-aspects如何使用AspectJ实现它们(这是一个简化的示例,您可以在MethodLogger.java找到完整的代码):

@Aspect
public class MethodLogger {@Around("execution(* *(..)) && @annotation(Loggable)")public Object around(ProceedingJoinPoint point) {long start = System.currentTimeMillis();Object result = point.proceed();Logger.info("#%s(%s): %s in %[msec]s",MethodSignature.class.cast(point.getSignature()).getMethod().getName(),point.getArgs(),result,System.currentTimeMillis() - start);return result;}
}

这是一个方面 ,里面有一个关于 around() 建议 。 方面用@Aspect注释,而建议用@Around注释。 如上所述,这些注释只是.class文件中的标记。 除了为那些对运行时感兴趣的人提供一些元信息外,他们什么也不做。

注释@Around有一个参数,在这种情况下,该参数表示在以下情况下建议应适用于方法:

  1. 其可见性修饰符为*publicprotectedprivate );
  2. 它的名字是名字* (任何名字);
  3. 它的参数是.. (任何参数); 和
  4. 它用@Loggable注释

如果要截获对带注释的方法的调用,则在执行实际方法之前,先执行方法around() 。 当要拦截对power()方法的调用时, around()方法将接收类ProceedingJoinPoint的实例,并且必须返回一个对象,该对象将作为power()方法的结果使用。

为了调用原始方法power() ,建议必须调用连接点对象的proceed()

我们编译此方面,并使其与主文件Foo.class一起在classpath中可用。 到目前为止,一切都很好,但是我们需要采取最后一步,以便将我们的方面付诸实践-我们应该应用我们的建议。

二元方面编织

方面编织是建议应用过程的名称。 Aspect Weaver通过注入对Aspect的调用来修改原始代码。 AspectJ正是这样做的。 我们给它提供了两个二进制Java类Foo.classMethodLogger.class ; 它给退三-修改Foo.classFoo$AjcClosure1.class和未修改MethodLogger.class

为了了解哪些建议应应用于哪些方法,AspectJ weaver使用了.class文件中的注释。 同样,它使用反射来浏览类路径上的所有类。 它通过@Around注释分析哪些方法满足条件。 当然,它找到我们的方法power()

因此,有两个步骤。 首先,我们使用javac编译.java文件,并获得两个文件。 然后,AspectJ编织/修改它们并创建自己的额外类。 编织后,我们的Foo类如下所示:

public class Foo {private final MethodLogger logger;@Loggablepublic int power(int x, int p) {return this.logger.around(point);}private int power_aroundBody(int x, int p) {return Math.pow(x, p);}
}

AspectJ weaver将我们的原始功能移动到新方法power_aroundBody() ,并将所有power()调用重定向到方面类MethodLogger

现在,我们有四个类一起工作,而不是Foo类中的power()方法。 从现在开始,这就是每次调用power()幕后发生的事情:

未命名

方法power()原始功能由图中的绿色小生命线指示。

如您所见,方面编织过程将类和方面连接在一起,并通过连接点在它们之间转移调用。 无需编织,类和方面都只是带有附加注释的已编译Java二进制文件。

jcabi方面

jcabi-aspects是一个JAR库,其中包含Loggable注释和MethodLogger方面(顺便说一句,还有更多方面和注释)。 您不需要编写自己的方面来进行方法记录。 只需在类路径中添加一些依赖项,然后配置jcabi-maven-plugin进行编织(在Maven Central中获取其最新版本):

<project><depenencies><dependency><dependency><groupId>com.jcabi</groupId><artifactId>jcabi-aspects</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId></dependency></dependency></depenencies><build><plugins><plugin><groupId>com.jcabi</groupId><artifactId>jcabi-maven-plugin</artifactId><executions><execution><goals><goal>ajc</goal></goals></execution></executions></plugin></plugins></build>
</project>

由于该编织过程需要大量的配置工作,因此我创建了一个方便的带有ajc目标的Maven插件,该插件可以完成整个方面的编织工作。 您可以直接使用AspectJ,但是我建议您使用jcabi-maven-plugin 。

而已。 现在,您可以使用@com.jcabi.aspects.Loggable注释,您的方法将通过slf4j记录。

如果某些内容无法按照说明进行操作,请随时提交Github问题 。

相关文章

您可能还会发现以下有趣的帖子:

  • 如何在异常上重试Java方法
  • 缓存Java方法结果
  • 摆脱Java静态记录器
  • 限制Java方法执行时间
  • 简单的Java SSH客户端

翻译自: https://www.javacodegeeks.com/2014/09/java-method-logging-with-aop-and-annotations.html

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

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

相关文章

mysql binlog空间维护

默认情况下&#xff0c;mysql主从同步的binlog日志&#xff0c;会一直保存。 对于如果已同步好的数据&#xff0c;这显然比较浪费资源。 且如果生产环境磁盘太小&#xff0c;随时还会爆掉&#xff0c;所以很有必要作好binlog的空间维护。 以下操作&#xff0c;直接在master上操…

一键发布到Maven Central的方法

当我向Maven Central发布Java开源库jcabi-aspects的新版本时&#xff0c;我花费了30秒钟的时间。 甚至更少。 最近&#xff0c;我发布了0.17.2版本。 您可以在Github第80期中看到所有情况&#xff1a; 如您所见&#xff0c;我向Rultor发出了命令&#xff0c;它向Maven Central…

在Spring Boot应用程序中测试邮件代码

在构建Spring Boot应用程序时&#xff0c;您可能会需要添加邮件配置。 实际上&#xff0c;在Spring Boot中配置邮件与在Spring Bootless应用程序中配置邮件没有太大区别。 但是&#xff0c;如何测试邮件配置和提交工作正常&#xff1f; 我们来看一下。 我假设我们有一个引导的…

es6笔记

es6对象浅复制&#xff1a; 字符串大小比较&#xff1a; 如果是汉字&#xff1a;a.charCodeAt() > b.charCodeAt() //使用carCodeAt将器转为asci码&#xff0c;在进行比较 如果是非汉字的字符串&#xff1a;直接比较或者使用上面的转码比较都可以。 如果是日期比较&#xff…

毕业设计上线啦!----跳蚤部落与基于Comet的WebIM系统开发

我不清楚把我的毕业设计的东西放上来之后&#xff0c;毕业论文答辩的时候会不会说我是在网上抄袭的&#xff0c;不过我还是果断的发上来与大家分享了&#xff01;&#xff01;呵呵&#xff0c;请大家支持&#xff01;高手就绕道吧&#xff01; 现在已经放到公网上&#xff0c;并…

poj2032Square Carpets(IDA* + dancing links)

题目请戳这里 题目大意:给一个H行W列的01矩阵,求最少用多少个正方形框住所有的1. 题目分析:又是一个红果果的重复覆盖模型.DLX搞之! 枚举矩阵所有的子正方形,全1的话建图.判断全1的时候,用了一个递推,dp[i][j][w][h]表示左上角(i,j)的位置开始长h宽w的矩形中1的个数,这样后面可…

具有Overlord的WildFly 8.1中的API管理

昨天&#xff0c;我简要介绍了霸王项目家族。 今天该试驾了。 API管理子项目两天前发布了1.0.0.Alpha1&#xff0c;并根据18个月的路线图介绍了第一组功能。 APIMan到底是什么&#xff1f; 它是一个API管理系统&#xff0c;可以嵌入现有框架或应用程序中&#xff0c;甚至可以作…

设计模式学习笔记-代理模式

1. 概述 为其它对象提供一种代理以控制对这个对象的访问。 解决的问题&#xff1a;如果直接访问对象比较困难&#xff0c;或直接访问会给使用者或系统带来一系列问题。这样对于客户端&#xff08;调用者&#xff09;来说&#xff0c;就不需要直接与真实对象进行交互&#xff0c…

Tomcat配置自签名https

从JDK中找到keytool.exe&#xff0c;随便复制到一个方便的目录&#xff0c;在命令行中进入这个目录。 第一步&#xff1a;为服务器生成证书 tomcat.keystore&#xff0c;名字就是域名&#xff0c;其他的看着写。 keytool -genkey -v -alias tomcat -keyalg RSA -validity 3650…

MFC学习之路之多媒体 --(1) DirectShow

可以说整个Windows的多媒体编程都是以DirectShow为基础&#xff0c;那好&#xff0c;来吧&#xff0c;我们直接看DirectShow的一段基础代码。 bool Mp3::Load(LPCWSTR szFile) {Cleanup();ready false;if (SUCCEEDED(CoCreateInstance( CLSID_FilterGraph,NULL,CLSCTX_INPROC_…

游戏大厅 从基础开始(6)--绕回来细说聊天室(中)之女仆编年史1

上一篇我们大致的了解了几种聊天室的行为模式 最简单明了的推模式 几乎不需要任何多余的语言来描述它的实现 这一篇我们看看如何实现拉模式更有效。 本图清晰的表现了"拉"模式聊天室的行为。 并发多用户向数据池写数据 并发多用户从数据池读书据 数据最好以时间为…

开发自上而下的Web服务项目

这是从Alessio Soldano编辑的Advanced JAX-WS Web Services手册中摘录的示例章节。 第一章介绍了自底向上创建Web服务端点的方法。 它允许非常快地将现有bean作为Web Service端点公开&#xff1a;在大多数情况下&#xff0c;将类转换为端点只需在代码中添加少量注释即可。 但…

垃圾收集:提高吞吐量

这篇文章的灵感来自于在内存管理术语中的“ Pig in the Python ”定义。 显然&#xff0c;该术语用于解释GC反复促进大对象世代相传的情况。 据推测&#xff0c;这样做的效果类似于Python吞下整个猎物&#xff0c;只是在消化过程中被固定住了。 在接下来的24小时里&#xff0c…

大叔手记(12):我的一次面试经历(谈大叔如何应对面试官)

本文目的 写本文的目的&#xff0c;大叔不是为了装逼&#xff08;虽然说话的口气有时候也确实有点装逼&#xff0c;性格导致的&#xff0c;咳。。。我得改&#xff09;&#xff0c;其实大叔在公司也只是小罗罗&#xff0c;本文的目的主要是为了向大家展示如何通过各种软技能应对…

认识Mahout下的云计算机器学习

认识Mahout下的云计算机器学习 Apache Mahout 是 ApacheSoftware Foundation (ASF) 旗下的一个开源项目&#xff0c;提供一些可扩展的机器学习领域经典算法的实现&#xff0c;旨在帮助开发人员更加方便快捷地创建智能应用程序&#xff0c;并且&#xff0c;在 Mahout 的最近版本…

NetBeans 8.0的五个新性能提示

NetBeans 8.0引入了几个新的Java提示 。 尽管有许多与Java Persistence API相关的新提示&#xff0c;但我还是关注Performance类别中的五个新提示。 NetBeans 8.0引入的五个新的“性能提示”是&#xff1a; 已装箱价值的装箱 冗余String.toString&#xff08;&#xff09; …

机智云小程序启蒙:WebSocket网页控制

机智云小程序启蒙&#xff1a;WebSocket网页控制 机智云Web版的JS远程控制设备&#xff0c;是调用了机智云开放的Open API和WebSocket API来实现的。这个是设计小程序最好的基础&#xff0c;也可以使无安卓设备的用户用网页远程控制设备。 其中&#xff0c;Open API用到的接口…

Web service 超过了最大请求长度错误解决

Web service 超过了最大请求长度错误解决 System.Web.Services.Protocols.SoapException: 运行配置文件中指定的扩展时出现异常。 ---> System.Web.HttpException: 超过了最大请求长度。 在 System.Web.HttpRequest.GetEntireRawContent() 在 System.Web.HttpRequest.ge…

动态规划--图像压缩

<算法设计与分析> --王晓东 题目描述和解析参照&#xff1a;http://blog.csdn.net/liufeng_king/article/details/8648195 他在那里分析得非常的详细。我也是按照这种思路来解的&#xff0c;而且算法设计与实现的课件上也是这么个解法。 主要是理解这个公式&#xff0c;…

oracle 存储过程的基本语法 及注意事项

oracle 存储过程的基本语法 1.基本结构 CREATE OR REPLACE PROCEDURE 存储过程名字( 参数1 IN NUMBER, 参数2 IN NUMBER) IS变量1 INTEGER :0;变量2 DATE;BEGIN END 存储过程名字2.SELECT INTO STATEMENT 将select查询的结果存入到变量中&#xff0c;可以同时将多个列存…