这里的问题不是 AspectJ,而是 JVM。在 Java 中,
永远不会 被 继承
注释继承仅适用于从类到子类,但前提是超类中使用的注释类型带有元注释 @Inherited
,请参阅 JDK JavaDoc .
AspectJ 是一种 JVM 语言,因此可以在 JVM 的限制范围内工作。这个问题没有通用的解决方案,但是对于您希望模拟注释继承的特定接口或方法,您可以使用如下解决方法:
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(类型间定义)机制将它们添加回接口以及所有实现/覆盖类/方法。
现在运行时控制台日志 Application
显示:
execution(de.scrum_master.app.Application())
execution(void de.scrum_master.app.Application.two())
顺便说一句,您也可以将方面直接嵌入到界面中,以便将所有内容放在一个地方。只需小心重命名, MyInterface.java
以 MyInterface.aj
帮助 AspectJ 编译器识别出它必须在此处执行一些工作。
package de.scrum_master.app;
public interface MyInterface {
void one();
void two();
// Cannot omit 'static' here due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=571104
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;
}
}
更新 2021-02-11: 有人建议对后一种解决方案进行修改,称 MarkerAnnotationInheritor
接口内部嵌套的 MyInterface
是隐式的 public static
,因此可以省略方面声明中的修饰符。原则上这是正确的,因为接口的成员(方法、嵌套类)默认情况下始终是公共的,并且非静态内部类定义在接口内部也没有意义(没有实例可以将其绑定到)。不过,我喜欢在示例代码中明确说明,因为并非所有 Java 开发人员都知道这些细节。
此外,目前版本 1.9.6 中的 AspectJ 编译器如果我们省略则会抛出错误 static
。我刚刚 针对此问题 AspectJ 问题 #571104