GUICE 中 AOP 的继承注解

Inheriting annotation for AOP in GUICE

我正在使用 Guice 和 AspectJ,我正在尝试做一些 AOP 来测量某些方法的执行时间。

我有这个注释,它将用于注释我需要测量的所有方法:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MyStopWatch {
}

我有这个方法拦截器:

public class MyInterceptor implements org.aopalliance.intercept.MethodInterceptor {
  private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    final org.apache.commons.lang3.time.StopWatch stopWatch = org.apache.commons.lang3.time.StopWatch.createStarted();
    final Object returnedObject = invocation.proceed();
    stopWatch.stop();

    logger.info("[STOPWATCH] Method: {} - Time: {}.", invocation.getMethod().getName(), stopWatch.getTime());

    return returnedObject;
  }
}

我有这个界面

public interface MySuperClass {
  @MyStopWatch
  default void test() {
    System.out.println("Hello, world");
  }
}

然后我有这个继承自 MySuperClass 的子类:

public class MySubClass implements MySuperClass {
}

最后,我有这个绑定:

public class MyAOPModule extends AbstractModule {
  @Override
  protected void configure() {
    bindInterceptor(
            Matchers.any(),
            Matchers.annotatedWith(MyStopWatch.class),
            new MyInterceptor()
    );
  }
}

我这样初始化我的 Guice 模块:

public static void main(String[] args) throws Throwable {
  Injector injector = createInjector(new MyAOPModule());
  injector.getInstance(MySubClass.class).test(); 
}

我的问题是没有任何记录,就好像子类对 test() 方法的执行没有被注释。

有什么办法可以解决这个问题?

这是一个 known and old issue,不太可能很快修复。

有几种方法可以避免这种情况,但 none 是标准方法。最有价值的出自这里:https://codingcraftsman.wordpress.com/2018/11/11/google-guice-aop-with-interface-annotations/

// the configure override of a Guice Abstract Module
@Override
protected void configure() {
  bindInterceptor(any(),
      // an instance of the matcher looking for HTTP methods
      new HasOrInheritsAnnotation(GET.class, PATCH.class, PUT.class, POST.class, DELETE.class),
      // the method interceptor to bind with
      new MyInterceptor());
}

还有 HasOrInheritsAnnotation class(我试图解决任何遗漏的通用问题,如果仍然存在,请编辑此答案以修复它):

/**
 * Matcher for methods which either have, or override a method which has a given
 * annotation type from the set.
 */
public class HasOrInheritsAnnotation extends AbstractMatcher<Method> {
  private final Set<Class<? extends Annotation>> annotationTypes;

  /**
   * Construct with the types of annotations required
   * @param annotationTypes which types of annotation make this matcher match
   */
  @SafeVarArgs
  public HasOrInheritsAnnotation(Class<? extends Annotation>... annotationTypes) {
    this.annotationTypes = ImmutableSet.copyOf(annotationTypes);
  }

  @Override
  public boolean matches(Method method) {
    // join this method in a stream with the super methods to fine
    // one which has the required annotation
    return Stream.concat(
          Stream.of(method),
          getSuperMethods(method))
        .anyMatch(this::hasARequiredAnnotation);
  }

  /**
   * Do any of the annotations on the method appear in our search list?
   * @param method the method to inspect
   * @return true if any of the annotations are found
   */
  private boolean hasARequiredAnnotation(Method method) {
    return Arrays.stream(method.getDeclaredAnnotations())
        .map(Annotation::annotationType)
        .anyMatch(annotationTypes::contains);
  }

  /**
   * Provide a stream of methods from all super types of this
   * @param method the method to search with
   * @return all methods that are overridden by <code>method</code>
   */
  private Stream<Method> getSuperMethods(Method method) {
    return streamOfParentTypes(method.getDeclaringClass())
        .map(clazz -> getSuperMethod(method, clazz))
        .filter(Optional::isPresent)
        .map(Optional::get);
  }

  /**
   * A stream of every parent type in the class hierarchy
   * @param declaringClass the class to read
   * @return a stream of the immediate parent types and their parents
   */
  private static Stream<Class<?>> streamOfParentTypes(Class<?> declaringClass) {
    return Stream.of(
        // all interfaces to the declaring class
        Arrays.stream(declaringClass.getInterfaces()),

        // all the parent types of those interfaces
        Arrays.stream(declaringClass.getInterfaces())
          .flatMap(HasOrInheritsAnnotation::streamOfParentTypes),

        // the super class of the declaring class
        Optional.ofNullable(declaringClass.getSuperclass())
          .map(Stream::of)
          .orElse(Stream.empty()),

        // any parents of the super class
        Optional.ofNullable(declaringClass.getSuperclass())
          .map(HasOrInheritsAnnotation::streamOfParentTypes)
          .orElse(Stream.empty()))

        // turn from a stream of streams into a single stream of types
        .flatMap(Function.identity());
  }

  /**
   * Search for the given method in a super class. In other words, which
   * is the super class method that the given method overrides?
   * @param method the method to match
   * @param superType the type to scan
   * @return an optional with the super type's method in, or empty if not found
   */
  private static Optional<Method> getSuperMethod(Method method, Class superType) {
    try {
      return Optional.of(superType.getMethod(method.getName(), method.getParameterTypes()));
    } catch (NoSuchMethodException e) {
      // this exception means the method doesn't exist in the superclass
      return Optional.empty();
    }
  }
}