Search code examples
javaaspectj

JAVA advice annotation will run twice?


In my case, I am using the following advice:

  @Around(value = "@annotation(MyAnnotation)  && args(MyArgs)")

and it works fine once the MyAnnotation is added to the method and MyArgs will also retrieved.

  @MyAnnotation(type = MyType.CREATE)
  public void add(MyArgs) { 
  ...
  }

But in this post, it says:

The errors that can and will occur

Using only annotations creates another problem that we don’t need to think about while using patterns; It will make our advice run twice(or more), because the annotation pointcut don’t specify if it should be run during execution or initialization.

To my understanding, it seems right once the join point reached and the condition is met, the advice should run (then my advice above will run twice - the call and the exeuction). And I should use the following advice to avoid it.

  @Around(value = "@annotation(MyAnnotation)  && execution(* *(..)) && args(MyArgs)")

But I debugged my code, it only runs once without adding execution(* *(..)).

Is this right? Or it's not the way in which advice runs?

Updated 2018-04-16

@Nandor is right, I was using Spring AOP instead of AspectJ. I started a maven demo clearly demonstating his point. Thank you, Nandor.


Solution

  • If you were using AspectJ, your advice would be triggered twice, because the pointcut expression

    @annotation(MyAnnotation)
    

    matches both method execution and method call join points. See call vs execution in the AspectJ programming guide. Since your pointcut expression is not restricted to either call or execution join points, it will match both. If you were actually using AspectJ in your project, your around advice would be triggered for both and you would face the issue you were warned about in the post you are referring to.

    The fact that using this pointcut expression doesn't result in the around advice executing twice means that you are in fact not using AspectJ and you're using Spring AOP instead, which only supports method execution pointcuts (see Spring AOP capabilities and goals)

    Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans).

    and only for public methods, because of the proxy based nature of Spring AOP (besides many other limitations).

    If you want to create pointcut expressions that would behave the same with both Spring AOP and AspectJ, make sure to always constrain the pointcut to method execution by adding the corresponding pointcut expression, for example:

    @annotation(MyAnnotation) && execution(public * *(..))