我有一个这样的日志记录方面,它会打印参数、结果或任何其他异常。我使用 aspectj-maven-plugin 来编译这方面。然后,将编译结果打包成一个jar。我会将这个 jar 提供给我们的 maven 存储库,这样他们就可以在他们的项目中依赖这个 jar。如果他们需要记录任何请求信息,他们只需要在方法定义处写一个注解@Log。我还想提供“包分配能力”:我的同事可以在编译他们的项目时设置一个包参数,然后在该包内调用的所有方法都将被删除。
综上所述,就像下面代码中的customPointCut,当我在另一个项目中需要这个编译的asject时,我想改变切入点定义。
@Aspect
public class LogAspect {
static private final Logger log = Logger.getLogger(LogAspect.class);
@Pointcut("execution(@com.stellariver.milky.aspectj.tool.log.Log * *(..))")
private void annoPointCut() {}
@Pointcut("execution(* com.project.package..*.*(..))")
private void customPointCut() {}
@Around("annoPointCut() || customPointCut()")
public Object valid(ProceedingJoinPoint pjp) throws Throwable {
Object result = null;
try {
result = pjp.proceed();
} catch (Throwable throwable) {
throw throwable;
} finally {
log(xx,xx);
}
return result;
}
}
我在方面项目或 aspect-maven-plugin 项目中找不到任何参数化的方面解决方案
在 Java 中,注释值必须是编译时常量,因此您不能更改它们。这不是 AspectJ 问题,而是 Java 限制。
所以你在 AspectJ 中所做的就是将你的日志方面定义为抽象的,并将包切入点也定义为抽象的:
@Aspect
public abstract class AutoLogAspect {
// (...)
@Pointcut("")
public abstract void packagePC();
// (...)
}
然后,在您的演示项目中,您覆盖抽象方面,定义一个具体的切入点:
package com.example.log.demo;
import com.stellariver.milky.aspectj.tool.log.AutoLogAspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyLogAspect extends AutoLogAspect {
@Pointcut("within(com.example.log..*) && execution(* *(..))")
public void packagePC() {}
}
现在,您可以从示例类中删除
@Log
注释:
package com.example.log.demo;
public class Main {
public static void main(String[] args) {
Fool fool = new Fool();
fool.testLogOfPackage("Hello World");
}
public static class Fool {
public void testLogOfPackage(String str) {
System.out.println(str);
}
}
}
使用Maven编译时,你会看到:
[INFO] --- aspectj-maven-plugin:1.14.0:compile (default) @ log-demo ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void com.example.log.demo.Main$Fool.testLogOfPackage(java.lang.String))' in Type 'com.example.log.demo.Main$Fool' (Main.java:10) advised by around advice from 'com.example.log.demo.MyLogAspect' (aspectj-tool-0.1.8-SNAPSHOT.jar!AutoLogAspect.class(from AutoLogAspect.java))
[INFO] Join point 'method-execution(void com.example.log.demo.Main.main(java.lang.String[]))' in Type 'com.example.log.demo.Main' (Main.java:4) advised by around advice from 'com.example.log.demo.MyLogAspect' (aspectj-tool-0.1.8-SNAPSHOT.jar!AutoLogAspect.class(from AutoLogAspect.java))
运行示例程序时,输出将是:
Hello World
=====msg: execution(Main.Fool.testLogOfPackage(..))
==header: 09:12:00.329 [main-INFO ] com.stellariver.milky.aspectj.tool.log.AutoLogAspect:386 : [success:true] [cost:0] [result:]
===milky: [class:com.stellariver.milky.aspectj.tool.log.AutoLogAspect] [method:log] [line:66]
====args: [arg0:Hello World] [arg1:] [arg2:] [arg3:] [arg4:] [arg5:]
=====msg: execution(Main.main(..))
==header: 09:12:00.334 [main-INFO ] com.stellariver.milky.aspectj.tool.log.AutoLogAspect:386 : [success:true] [cost:7] [result:]
===milky: [class:com.stellariver.milky.aspectj.tool.log.AutoLogAspect] [method:log] [line:66]
====args: [arg0:[Ljava.lang.String;@4ff4357f] [arg1:] [arg2:] [arg3:] [arg4:] [arg5:]
看到了吗?无需复制和粘贴整个方面。您只需将包切入点抽象化并强制使用项目覆盖它。干净简单。
P.S.:如果消费项目使用加载时织入而不是编译时织入,您可以直接在 aop.xml 中定义覆盖方面,根本不需要编译源方面或使用 AspectJ Maven 插件消费项目。但是 CTW 或 LTW,两者都很好用,剩下的就看你了。