Spring AOP:捕获了带有参数注释的接口方法,但注释不存在

Spring AOP : Interface method with Parameter annotation captured, but annotation is not present

我正在使用 Spring AOP 来拦截方法执行。

我的界面如下所示:

public interface MyAwesomeService {
    public Response doThings(int id, @AwesomeAnnotation SomeClass instance);
}

接口实现如下:

public class MyAwesomeServiceImpl implements MyAwesomeService {
    public Response doThings(int id, SomeClass instance) {
        // do something.
    }
}

现在,我希望任何带有 @AwesomeAnnotation 注释参数的方法都应该被 Spring AOP 捕获。

所以我写了以下方面,有效

@Aspect
@Component
public class MyAwesomeAspect {
    @Around("myPointcut()")
    public Object doAwesomeStuff(final ProceedingJoinPoint proceedingJoinPoint) {
         final MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
         Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();

         // annotationMatrix is empty.
    }

    @Pointcut("execution(public * *(.., @package.AwesomeAnnotation  (package.SomeClass), ..))")
    public void myPointcut() {}
}

但是,当我尝试查找参数注释时,我没有得到任何注释。上面说了annotationMatrix是空的

所以这是我的问题:

  1. 为什么annotationMatrix是空的?可能是因为参数注释不是从接口继承的。
  2. 为什么我能够捕获方法执行。由于 Spring AOP 能够匹配切入点,因此 Spring 能够以某种方式看到方法的参数注释,但是当我尝试使用 methodSignature.getMethod().getParameterAnnotations() 看到它时,它不起作用。

我的一个参数注释也遇到了这个问题。我能够通过确保参数注释定义将 RetentionPolicy 作为 RUNTIME 并将 Target 作为 PARAMETER

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {

    public String name();

}

您问题的答案:

  1. 参数注释不是从接口继承到实现方法。事实上,注解几乎从不被继承,如果注解类型本身被@Inherited注解,只能从class(不是接口!)到subclass,参见JDK API documentation更新: 因为我之前已经多次回答过这个问题,所以我刚刚在 .

  2. 中记录了这个问题和解决方法
  3. 因为在编译或编织期间,AspectJ 可以将切入点与接口方法进行匹配,从而看到注释。

您可以通过在接口实现中的参数中添加注释来解决这个问题,例如像这样:

@Override
public Response doThings(int id, @AwesomeAnnotation SomeClass instance) {
    // ...
}

然后像这样的相位...

@Aspect
@Component
public class MyAwesomeAspect {
    @Pointcut("execution(public * *..MyAwesomeService.*(*, @*..AwesomeAnnotation (*), ..)) && args(*, instance, ..)")
    static void myPointcut(SomeClass instance) {}

    @Around("myPointcut(instance)")
    public Object doAwesomeStuff(Object instance, ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println(proceedingJoinPoint);
        System.out.println("  instance = " + instance);
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
         Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
         for (Annotation[] annotations : annotationMatrix) {
             for (Annotation annotation : annotations) {
                 System.out.println("  annotation = " + annotation);
             }
         }
         return proceedingJoinPoint.proceed();
    }
}

...你会得到类似这样的控制台日志:

execution(Response de.scrum_master.app.MyAwesomeServiceImpl.doThings(int, SomeClass))
  instance = de.scrum_master.app.SomeClass@23fc625e
  annotation = @de.scrum_master.app.AwesomeAnnotation()