匹配特定注释参数值的 aspectj 切入点

aspectj pointcut matching a specific annotation parameter value

我正在尝试围绕使用自定义注释进行注释的方法定义切入点。注释有一个参数,我想在切入点定义中包含一个检查。

这是注释:

public @interface MyAnno {
  String[] types;
}

如何应用注释的示例:

public class MyClass {
  @MyAnno(types={"type1", "type2"})
  public void doSomething() {
    // ...
  }
  @MyAnno(types={"type3"})
  public void doSomethingElse() {
    // ...
  }
}

现在我想有两个切入点定义,select 这两个方法,基于注释的内容。

在注释本身上创建切入点相对容易:

@Pointcut("@annotation(myAnno)")
public void pointcutAnno(MyAnno myAnno) {
}

@Pointcut("execution(* *(..)) && pointcutAnno(myAnno)")
public void pointcut(MyAnno myAnno) {
}

这将匹配 @MyAnno 的每次出现。但是我如何定义两个切入点,一个匹配 @MyAnnotypes 包含 "type1",另一个匹配 @MyAnnotypes 包含 "type3"

目前,AspectJ 支持对允许的注释值类型的子集进行注释值匹配。不幸的是,不支持您使用的数组类型(也不支持 class)。此功能记录在 1.6.0 AspectJ 自述文件 (https://eclipse.org/aspectj/doc/released/README-160.html) 中。 'Annotation value matching' 上有一节。如那里所述,对于基本情况,语法实际上非常直观:

enum TraceLevel { NONE, LEVEL1, LEVEL2, LEVEL3 }

@interface Trace {
  TraceLevel value() default TraceLevel.LEVEL1;
}

aspect X {
  // Advise all methods marked @Trace except those with a tracelevel of none
  before(): execution(@Trace !@Trace(TraceLevel.NONE) * *(..)) {
    System.err.println("tracing "+thisJoinPoint);
  }
}

因此,只需在注释中包含您要匹配的值即可。不幸的是,数组的情况更复杂,所以还没有实现。它需要更多的语法来允许您指定切入点是指 'at least this in the array value' 还是 'exactly this and only this in the array value'。大概会重用 .. 符号,可能是这样的:

execution(@MyAnno(types={"type1"}) * *(..)) { // exactly and only 'type1'
execution(@MyAnno(types={"type1",..}) * *(..)) { // at least 'type1'

如果没有语言支持,恐怕您必须以编程方式挖掘代码中的注释以检查它是否符合您的约束条件。

您可以使用条件切入点来完成,但这些切入点将涉及对注释属性的运行时测试。

原生方面语法:

pointcut p(MyAnno myAnno): execution(* *(..)) 
    && @annotation(myAnno) 
    && if(Arrays.stream(myAnno.types()).anyMatch("type1"::equals));

基于注释的方面语法:

@Pointcut("execution(* *(..)) && @annotation(myAnno) && if()")
public boolean pointcut(MyAnno myAnno) {
    return !Arrays.stream(myAnno.types()).anyMatch("type1"::equals);
}

不要忘记为两个示例导入 java.util.Arrays

目前,从 AspectJ 版本 1.8.13 开始,您不能像使用非数组类型属性那样静态限制数组类型注释属性上的切入点表达式,因此该解决方案将涉及运行时测试。