I have a logging aspect like this, it will print args, result or any other exceptions. I use aspectj-maven-plugin to compile this aspect. Then, the compiled result will be packaged to a jar. I will offer this jar to our maven repository, so they can depend this jar in their project. If they need log any request info, they just need write an annonation @Log at the method defination. I aslo want to offer "a package assign abilility": My colleage could set a package parameter when compile their project, then all the method invoke inside that package will be cut。
In summary, like the customPointCut in the following code, I want change the pointcut defination when I need this compiled asject in another project.
@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;
}
}
I could not find any parameterized aspect solution in aspect project or aspect-maven-plugin project
In Java, annotation values must be compile-time constants, so you cannot change them. This is not an AspectJ issue, but a Java limitation.
So what you do in AspectJ is to define your logging aspect as abstract and the package pointcut also as abstract:
@Aspect
public abstract class AutoLogAspect {
// (...)
@Pointcut("")
public abstract void packagePC();
// (...)
}
Then, in your demo project, you override the abstract aspect, defining a concrete pointcut:
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() {}
}
Now, you can remove the @Log
annotation from your sample class:
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);
}
}
}
When compiling with Maven, you willl see:
[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))
When running the sample program, the output will be:
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:]
See? There is no need to copy & paste the whole aspect. You simply make the package pointcut abstract and force consuming projects to override it. Clean and simple.
P.S.: If the consuming project would use load-time weaving instead of compile-time weaving, you could define the overriding aspect in aop.xml directly, no need to compile a source aspect or use AspectJ Maven Plugin at all in the consuming project. But CTW or LTW, both works nicely, the rest is up to you.