昨天刚刚侍弄完 Spring 下基于自定义注解拦截方法调用,现在试下纯 AspectJ 的方式来打造,因为不是每一个项目都是 Spring。这次要推到 5 年前试验过用 javac 命令行编译的方式织入方面,见 AspectJ 基于自定义的方法注解来拦截方法,这次着重在用 aspectj-maven-plugin 插件的方法来织入 AspectJ 方面。
基本上代码还是昨天的,需求还是一样的:
被 @LogStartTime 注解的方法在进入该方法时记录当前时间在 ThreadLocal 中,并能根据 @LogStartTime 的属性值决定处理逻辑
因为 Java5+ 之后 AspectJ 可以写成 Java 类加注解的方式,*.aj 文件一般都没太大必要了,所以可以和 Spring AOP 共用一个 @Aspect 注解的方面代码 MethodStartAspect
。
我们将采用编译器织入,因此项目依赖只需要一个 org.aspectj:aspectjrt:1.8.0
, 它也不会引入别的组件。同样我们从 Main 方法和测试用例两方面来验证实现的效果,下面是整个测试项目的布局,以及依赖,除掉单元测试的其时就只需要一个 jar 包。
继续罗列代码
@LogStartTime, 注解被拦截的方法
1 2 3 4 5 |
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogStartTime { String value() default ""; } |
MethodStartAspect, 定义切面和 Advice
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Aspect public class MethodStartAspect {
private static ThreadLocal<Long> startTime = new ThreadLocal<>();
@Pointcut("execution(* cc.unmi..*(..)) && @annotation(logStartTime)") private void logStartTimePointcut(LogStartTime logStartTime) {
}
@Before("logStartTimePointcut(logStartTime)") public void setStartTimeInThreadLocal(LogStartTime logStartTime) { System.out.println(logStartTime.value()); startTime.set(System.currentTimeMillis()); System.out.println("saved method start time in threadLocal"); }
public static Long getStartTime() { return startTime.get(); }
public static void clearStartTime() { startTime.set(null); } } |
只要用 @Aspect
标识出它是一个 Aspect, 或者也可以完全用 AspectJ 语法,创建 *.aj 文件,里面写 public aspect MethodStartAspect
这样的的定义。在进入有注解 @LogStartTime
方法之前把当前时间写到 ThreadLocal 中去,并可读取注解的属性值。
UserService, 被拦截的方法用了 @LogStartTime 注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class UserService {
@LogStartTime(&# |