Spring AspectJ, pointcut before method execution where method OR class is annotated

后端 未结 1 1324
春和景丽
春和景丽 2020-12-11 09:02

I\'m trying to get the value of an annotation via Spring Aop AspectJ-style, where the annotation can be on the class OR the method. I tried a lot of different things, but I

相关标签:
1条回答
  • 2020-12-11 09:50

    Short answer

    While you can formulate a pointcut that will match both directly annotated methods and methods of annotated types at the same time, you cannot make a pointcut and/or advice where you bind the value of the annotation (i.e. use the annotation value in the advice code).

    @Aspect
    public class MyAspect {
    
        @Pointcut("execution(@com.myco.MyAnnotation * com.myco.somepackage..*.*(..))")
        public void atExecutionOfAnnotatedMethod() {}
    
        @Pointcut("execution(* (@com.myco.MyAnnotation com.myco.somepackage..*).*(..))")
        public void atExecutionOfMethodsOfAnnotatedClass() {}
    
        @Before("atExecutionOfAnnotatedMethod() && @annotation(myAnnotation)")
        public void myAdviceForMethodAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
            System.out.println("myAdviceForMethodAnnotation: " + myAnnotation.value());
        }
    
        @Before("atExecutionOfMethodsOfAnnotatedClass() && @this(myAnnotation)")
        public void myAdviceForTypeAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
            System.out.println("myAdviceForTypeAnnotation: " + myAnnotation.value());
        }
    
        //      /* the following pointcut will result in "inconsistent binding" errors */
        //      @Pointcut("(atExecutionOfAnnotatedMethod() && @annotation(myMethodAnnotation)) || (atExecutionOfMethodsOfAnnotatedClass() && @this(myTypeAnnotation))")
        //      public void combinedPointcut(MyAnnotation myMethodAnnotation, MyAnnotation myTypeAnnotation) {}
    
    }
    

    Some detail

    To combine the two separate pointcuts (atExecutionOfAnnotatedMethod and atExecutionOfMethodsOfAnnotatedClass) we would have to use the OR (||) construct. Since the OR construct doesn't guarantee that either of the two annotation bindings will be present at advice execution, they will both result in a compile error (inconsistent binding). You can still handle both cases in separate advices, you may also delegate the actual advice code to a common method to avoid duplication. In that case you'll need to take care of the case where both the type and the method is annotated with @MyAnnotation because that would match both pointcuts and would result in your method doubly advised by both advices, hence your common advice handling code will execute twice.

    Combining the two

    If you need to combine the two cases while defending against doubly advising the target code, you need to set up a precedence between the method level annotation and the class level annotation. Based on the principle of specificity, I'd suggest to go on the route where the method level annotation takes precedence over the class level one. Your aspect would look like this:

    @Aspect
    public class MyCombinedAspect {
    
        @Pointcut("execution(@com.myco.MyAnnotation * com.myco.somepackage..*.*(..))")
        public void atExecutionOfAnnotatedMethod() {}
    
        @Pointcut("execution(* (@com.myco.MyAnnotation com.myco.somepackage..*).*(..))")
        public void atExecutionOfMethodsOfAnnotatedClass() {}
    
        @Before("atExecutionOfAnnotatedMethod() && !atExecutionOfMethodsOfAnnotatedClass() && @annotation(myAnnotation)")
        public void myAdviceForMethodAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
            handleBeforeExecution(joinPoint, myAnnotation);
        }
    
        @Before("atExecutionOfMethodsOfAnnotatedClass() && !atExecutionOfAnnotatedMethod() && @this(myAnnotation)")
        public void myAdviceForTypeAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
            handleBeforeExecution(joinPoint, myAnnotation);
        }
    
        @Before("atExecutionOfMethodsOfAnnotatedClass() && atExecutionOfAnnotatedMethod() && @annotation(myMethodAnnotation)")
        public void myAdviceForDoublyAnnotated(JoinPoint joinPoint, MyAnnotation myMethodAnnotation) {
            handleBeforeExecution(joinPoint, myMethodAnnotation);
        }
    
        protected void handleBeforeExecution(JoinPoint joinPoint, MyAnnotation myAnnotation) {
            System.out.println(myAnnotation.value());
        }
    
    0 讨论(0)
提交回复
热议问题