GUICE中继承AOP注解 [英] Inheriting annotation for AOP in GUICE

查看:26
本文介绍了GUICE中继承AOP注解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using Guice and AspectJ, and I am trying to do some AOP to measure the execution time of certain methods.

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

I have this annotation which will be used to annotate all the methods I need to measure:

@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 的子类:

Then I have this subclass which inherits from MySuperClass:

public class MySubClass implements MySuperClass {
}

最后,我有了这个绑定:

And finally, I have this bind:

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

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

I initialize my Guice module like this:

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

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

My problem is that there is nothing being logged, as if the subclass's execution of the test() method was not annotated.

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

Any way I can go around this?

推荐答案

这是一个已知和老问题,不太可能很快解决.

This is a known and old issue and is unlikely to be fixed soon.

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

There exist several ways to avoid this, but none are standard. The one with the most merit comes from here: 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 类(我尝试解决任何缺失的通用问题,如果仍然存在,请编辑此答案以修复它):

And the HasOrInheritsAnnotation class (I tried to resolve any missing generic issue, if any persists, please edit this answer to fix it):

/**
 * 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();
    }
  }
}

这篇关于GUICE中继承AOP注解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆