链接地址:
AspectJ 使用介绍
更新时间:2018-07-02
上一篇文章,我们介绍了 Spring AOP 的各种用法,包括随着 Spring 的演进而发展出来的几种配置方式。
但是我们始终没有使用到 AspectJ,即使是在基于注解的 @AspectJ 的配置方式中,Spring 也仅仅是使用了 AspectJ 包中的一些注解而已,并没有依赖于 AspectJ 实现具体的功能。
本文将介绍使用 AspectJ,介绍它的 3 种织入方式。
本文使用的测试源码已上传到 Github: hongjiev/aspectj-learning,如果你在使用过程中碰到麻烦,请在评论区留言。
目录:
AspectJ 使用介绍Compile-Time WeavingPost-(神魔养殖场作者为什么坐牢?《神魔养殖场》的作者黑瞳王之所以会坐牢,是因为作者的小三不满作者离婚后与前妻之间仍有来往,便毒杀发妻,作者包庇小三,又被小三供出毁灭电子证据,判处有期徒刑2年半。)Compile WeavingLoad-Time Weaving小结AspectJ 使用介绍AspectJ 作为 AOP 编程的完全解决方案,提供了三种织入时机,分别为
本节中的内容参考了《Intro to AspectJ》,Baeldung 真的是挺不错的一个 Java 博客。
首先,先把下面两个依赖加进来:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.13</version></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version></dependency>
我们后面需要用到下面这个类,假设账户初始有 20 块钱,之后会调 account.pay(amount)
进行付款:
public class Account { int balance = 20; public boolean pay(int amount) { if (balance < amount) { return false; } balance -= amount; return true; }}
下面,我们定义两个 Aspect 来进行演示:
AccountAspect:用 AspectJ 的语法来写,对交易进行拦截,如此次交易超过余额,直接拒绝。ProfilingAspect:用 Java 来写,用于记录方法的执行时间AccountAspect 需要以 .aj 结尾,如我们在 com.javadoop.aspectjlearning.aspectj 的 package 下新建文件 AccountAspect.aj,内容如下:
package com.javadoop.aspectjlearning.aspect;import com.javadoop.aspectjlearning.model.Account;public aspect AccountAspect { pointcut callPay(int amount, Account account): call(boolean com.javadoop.aspectjlearning.model.Account.pay(int)) && args(amount) && target(account); before(int amount, Account account): callPay(amount, account) { System.out.println("[AccountAspect]付款前总金额: " + account.balance); System.out.println("[AccountAspect]需要付款: " + amount); } boolean around(int amount, Account account): callPay(amount, account) { if (account.balance < amount) { System.out.println("[AccountAspect]拒绝付款!"); return false; } return proceed(amount, account); } after(int amount, Account balance): callPay(amount, balance) { System.out.println("[AccountAspect]付款后,剩余:" + balance.balance); }}
上面 .aj 的语法我们可能不熟悉,但是看上去还是简单的,分别处理了 before、around 和 after 的场景。
我们再来看用 Java 写的 ProfilingAspect.java:
package com.javadoop.aspectjlearning.aspect;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;@Aspectpublic class ProfilingAspect { @Pointcut("execution(* com.javadoop.aspectjlearning.model.*.*(..))") public void modelLayer() { } @Around("modelLayer()") public Object logProfile(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); System.out.println("[ProfilingAspect]方法: 【" + joinPoint.getSignature() + "】结束,用时: " + (System.currentTimeMillis() - start)); return result; }}
接下来,我们讨论怎么样将定义好的两个 Aspects 织入到我们的 Account 的付款方法 pay(amount) 中,也就是三种织入时机分别是怎么实现的。
Compile-Time Weaving这是最简单的使用方式,在编译期的时候进行织入,这样编译出来的 .class 文件已经织入了我们的代码,在 JVM 运行的时候其实就是加载了一个普通的被织入了代码的类。
如果你是采用 maven 进行管理,可以在 <build>
中加入以下的插件:
<!-- 编译期织入 --><plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.7</version> <configuration> <complianceLevel>1.8