用aspectj实现日志记录

用aspectj实现日志记录

简介

记录日志在很多情况下都是必需的。但很多时候,日志与逻辑的代码混杂,让人难以阅读代码。如果能将记录日志与代码逻辑分离,就可以在满足日志需求的同时,让代码更加简明了。可以使用aspectj来达到这一目的。

aspectj提供了面向切面编程的功能。他可以“切开”原本的代码,并在切面上插入另一些代码,达到更改代码的目的。这个功能正适合于记录日志的场景。

在项目中使用aspectj

因为aspectj自己的编译过程,所以并不是加一个库就可以的。如果使用IDE编程,还需要设置相应的环境。eclipse有相应的插件,intellij pro支持aspectj功能,maven也有相应的插件。

我自己使用的是intellij community,所以并没有原生支持aspectj,不过它支持maven,所以我用了maven项目,通过一些配置,也可以达到在IDE中使用aspectj的目的。

在maven中加入aspectj的运行时库:

在maven中加入aspectj编译的插件,这里使用了一个第三方的插件:

加入这些之后,就可以编写和编译包含aspectj的程序了。但是仍然不能在intellij里运行和调试,因为intellij默认不会编译aspectj相关内容的。为此,可以在maven project窗口中将apectj compile设置成为运行前自动执行(做法如下图)。这样每次运行时就会自动编译aspectj了。

编写aspectj

aspectj有两种写法,一是使用独特的语法,文件扩展名为aj,二是使用aspectj的注解。因为intellij community没有支持aspectj,aj文件也没有编辑器,所以在这里我使用了注解的方式来编写aspectj。

首先我定义了一个aspect类,这个类带有@Aspect注解,aspectj在编译时会查看所有的类,如果它带有这个注解,就认为这个类不是普通的类,而是定义了切面相关的信息。

下一步就是定义切点,在刚才的类中,加入切点的定义。切点使用空方法加上@Pointcut注解来定义,注解中有一个字符串参数,定义了切点的信息。在allMethodCutpoint中使用了executionwithin两个配置。execution定义切点是切在执行方法时,其参数为方法的全定义,可以用通配符来定义。这里的* *..*(..)中的第一个*表示这是一个方法而不是类,*..*是方法全称,*代替任何不含.的字符串,..代替含.的字符串,(..)表示参数列表。within定义切点所在的位置,配置间也可以用逻辑运算符连接。所以这个切点的意思是匹配所有方法,除了当前切面内的方法。对于一些切面,如果不去掉切面内的方法的话,可能会产生栈溢出的问题。

最后是定义插入的内容,在aspectj中,这些内容被称为advice。还是在刚才的切面中,编写一个方法,方法的内容是要插入的内容。给方法加入@Before注解,这个注解表示在切点之前加入内容,它包含了一个参数,表示要插入的切点。

另外建一个类,加入空的main方法,运行,发现输出:

这说明在main方法调用前这一切点上,加入了我们想运行的代码。

处理运行错误

如果出现了Duplicate Name&Signature的错误,可以修改maven的编译过程,让切面类不被Java编译,而是之后被aspectj编译:

记录方法信息

可以看到这段程序中没有任何外部信息,比如被调用的方法等等,这样是无法记录成日志的。aspectj提供了JoinPoint类,用来记录切点的信息,只需要将它加入参数,就可以使用它。

重新运行,输出:

过滤日志和自定义信息

上面的例子里会给所有方法加上日志,但很多时候大部分方法我们都不需要给他们加日志。另一方面,日志的内容应该能够让用户自己定义,给不同的类加上不同的信息,而不是千篇一律。为了达到这个目的,可以自定义注解,并且使用aspectj在切点处读取参数的功能。

首先自定义注解:

然后定义切点和要插入的内容:

相比之前的切点,这个切点增加了一个配置:@annotation,这个配置会检查切点对应目标的注解,配置参数为一个变量名,这个变量名对应的变量在切点方法里作为参数传入,并指定了类型GodLog。所以,这个配置的意思是匹配含有GodLog注解的目标。同样,这个注解可以在@Before指定的方法内得到,也是基于变量名相同的准则。

因为限定了条件,所以要在main方法前加上@GodLog

执行,就会输出:

总结

aspectj能够做到的功能远远不止于此,它可以在几乎任何地方插入切点,也就意味着可以用这个方法在很多地方插入日志。本文只是简单应用了aspectj,如果能够深入了解并使用aspectj,一定能够达到方便神奇的效果。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*