Search code examples
aopaspectj

Aspectj woven both annotated methodA and methodB calling methodA


for example:I want to implement an AOP retry function

@Pointcut("@annotation(retryed)")
public void retry(Retry retryed) {}

@Around("retry(retryed)")
public Object process(ProceedingJoinPoint pjp, Retry retryed) throws Throwable {
    Object result = null;
    for (int i = 0; i < 2; i++) {
        result = pjp.proceed();
    }
    return result;
}



@Test
public void test() throws Exception {
    unAnnotatedMethodC();
}
private void unAnnotatedMethodC() {
    System.out.println("unAnnotatedMethodC");
    unAnnotatedMethodB();
}
private void unAnnotatedMethodB() {
    System.out.println("unAnnotatedMethodB");
    annotatedMethodA();
}
@Retry
private void annotatedMethodA() {
    System.out.println("annotatedMethodA");
}

output:

unAnnotatedMethodC
unAnnotatedMethodB
annotatedMethodA
annotatedMethodA
annotatedMethodA
annotatedMethodA

look the .class file

it has woven twice,its not i hope,i want output like this

unAnnotatedMethodC
unAnnotatedMethodB
annotatedMethodA
annotatedMethodA

How can I avoid this problem?


Solution

  • Your pointcut expression matches both execution and call type pointcuts, that's why you get double matches. execution type pointcuts match the location of the method's bytecode, while call type pointcuts will match the bytecode of the call sites of code invoking those methods. You'll need to restrict your code to execution type pointcuts to avoid invoking the around advice twice:

    @Pointcut("@annotation(retryed) && execution(* *(..))")
    

    See call vs execution in the AspectJ programming guide for further reference.