【问题标题】:Spring AOP : Interface method with Parameter annotation captured, but annotation is not presentSpring AOP:捕获参数注释的接口方法,但不存在注释
【发布时间】:2016-06-03 08:25:08
【问题描述】:

我正在使用 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() 查看时,它不起作用。

【问题讨论】:

    标签: aspectj spring-aop pointcut aspects spring-aspects


    【解决方案1】:

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

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface Param {
    
        public String name();
    
    }
    

    【讨论】:

    • 是的,注解有正确的目标和保留:
       @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface AwesomeAnnotation { long value() default -1 ; } 
    【解决方案2】:

    您的问题的答案:

    1. 参数注释不会从接口继承到实现方法。事实上,注解几乎从不被继承,如果注解类型本身被@Inherited注解,只能从类(不是接口!)到子类,参见JDK API documentation更新:因为我之前已经多次回答过这个问题,所以我刚刚在Emulate annotation inheritance for interfaces and methods with AspectJ 中记录了这个问题以及解决方法。

    2. 因为在编译或编织期间,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()
    

    【讨论】:

    • 感谢您的回复。我确实怀疑 AspectJ 可能会查看界面以发现注释。而且由于在运行时来自接口的注释没有被传递,我没有看到任何注释信息。我解决这个问题的方式与您指出的方式略有不同。我正在查看接口,看看接口定义上是否存在注释。
    猜你喜欢
    • 2018-07-24
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多