本文介绍了使用AspectJ模拟接口和方法的注释继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

人们经常会问AspectJ这样的问题,所以我想在以后可以轻松链接的地方回答。

我有这个标记注释:

package de.scrum_master.app;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Marker {}

现在我注释一个接口和/或类似的方法:

Now I annotate an interface and/or methods like this:

package de.scrum_master.app;

@Marker
public interface MyInterface {
  void one();
  @Marker void two();
}

这是一个小驱动程序应用程序,它也实现了接口:

Here is a little driver application which also implements the interface:

package de.scrum_master.app;

public class Application implements MyInterface {
  @Override
  public void one() {}

  @Override
  public void two() {}

  public static void main(String[] args) {
    Application application = new Application();
    application.one();
    application.two();
  }
}

现在,当我定义这个方面时,我希望它触发

Now when I define this aspect, I expect that it gets triggered


  • 每个构造函数执行带注释的类,

  • 每次执行带注释的方法。

package de.scrum_master.aspect;

import de.scrum_master.app.Marker;

public aspect MarkerAnnotationInterceptor {
  after() : execution((@Marker *).new(..)) && !within(MarkerAnnotationInterceptor) {
    System.out.println(thisJoinPoint);
  }

  after() : execution(@Marker * *(..)) && !within(MarkerAnnotationInterceptor) {
    System.out.println(thisJoinPoint);
  }
}

不幸的是,方面什么都不打印,就像上课一样应用程序和方法 two()没有任何 @Marker 注解。为什么AspectJ不拦截它们?

Unfortunately the aspect prints nothing, just as if class Application and method two() did not have any @Marker annotation. Why does AspectJ not intercept them?

推荐答案

这里的问题不是AspectJ而是JVM。在Java中,注释

The problem here is not AspectJ but the JVM. In Java, annotations on


  • 接口,

  • 方法或

  • 其他注释

永远不会继承


  • 使用带注释的注释实现类,

  • 覆盖方法或

  • 类。

注释继承仅适用于从类到子类,但仅当超类中使用的注释类型带有元注释 @Inherited 时,请参阅。

Annotation inheritance only works from classes to subclasses, but only if the annotation type used in the superclass bears the meta annotation @Inherited, see JDK JavaDoc.

AspectJ是一种JVM语言,因此可以在JVM的限制范围内工作。此问题没有通用的解决方案,但对于您希望模拟注释继承的特定接口或方法,您可以使用这样的解决方法:

AspectJ is a JVM language and thus works within the JVM's limitations. There is no general solution for this problem, but for specific interfaces or methods you wish to emulate annotation inheritance for, you can use a workaround like this:

package de.scrum_master.aspect;

import de.scrum_master.app.Marker;
import de.scrum_master.app.MyInterface;

/**
 * It is a known JVM limitation that annotations are never inherited from interface
 * to implementing class or from method to overriding method, see explanation in
 * <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html">JDK API</a>.
 * <p>
 * Here is a little AspectJ trick which does it manually.
 *
 */
public aspect MarkerAnnotationInheritor {
  // Implementing classes should inherit marker annotation
  declare @type: MyInterface+ : @Marker;
  // Overriding methods 'two' should inherit marker annotation
  declare @method : void MyInterface+.two() : @Marker;
}

请注意:有了这方面,你可以从界面和带注释的方法中删除(文字)注释,因为AspectJ的ITD(类型间定义)机制将它们添加回接口以及所有实现/重写类/方法。

Please note: With this aspect in place, you can remove the (literal) annotations from the interface and from the annotated method because AspectJ's ITD (inter-type definition) mechanics adds them back to the interface plus to all implementing/overriding classes/methods.

现在运行应用程序时的控制台日志说:

Now the console log when running the Application says:

execution(de.scrum_master.app.Application())
execution(void de.scrum_master.app.Application.two())

顺便说一下,您还可以将方面直接嵌入到界面中,以便将所有内容放在一个位置。小心将 MyInterface.java 重命名为 MyInterface.aj ,以帮助AspectJ编译器识别它具有在这里做一些工作。

By the way, you could also embed the aspect right into the interface so as to have everything in one place. Just be careful to rename MyInterface.java to MyInterface.aj in order to help the AspectJ compiler to recognise that it has to do some worke here.

package de.scrum_master.app;

public interface MyInterface {
  void one();
  void two();

  public static aspect MarkerAnnotationInheritor {
    // Implementing classes should inherit marker annotation
    declare @type: MyInterface+ : @Marker;
    // Overriding methods 'two' should inherit marker annotation
    declare @method : void MyInterface+.two() : @Marker;
  }
}

这篇关于使用AspectJ模拟接口和方法的注释继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 13:42
查看更多