是否可以将 类 包含在他们在 aop.xml 上的注释中?

Is it possible to include classes to be weaved by their annotations on aop.xml?

我正在开发一些预期会使用@AnAnnotation 进行加载时编织的方面 类。我创建了 aop.xml 如下

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

    <weaver options="-verbose -showWeaveInfo">
        <include within="@com.example.MyAnnotation *" />
    </weaver>

    <aspects>
        <aspect name="com.example.MyAspect" />
    </aspects>

</aspectj>

根据日志,我的方面似乎尝试建议适当 类 但紧接着发生以下异常。

java.lang.NoSuchMethodError: com.example.MyAspect.aspectOf

有什么想法吗?

:log

[ERROR] [AppClassLoader@2b193f2d] info AspectJ Weaver Version 1.9.7 built on Thursday Jun 24, 2021 at 16:14:45 PDT
[ERROR] [AppClassLoader@2b193f2d] info register classloader jdk.internal.loader.ClassLoaders$AppClassLoader@2b193f2d
[ERROR] [AppClassLoader@2b193f2d] info using configuration project/target/classes/META-INF/aop.xml
[ERROR] [AppClassLoader@2b193f2d] info register aspect com.example.MyAspect
[ERROR] [AppClassLoader@2b193f2d] weaveinfo Join point 'constructor-execution(void com.example.MyAspectTest$MyTargetClass.<init>(com.example.MyAspectTest, java.lang.String))' in Type 'com.example.MyAspectTest$MyTargetClass' (MyAspectTest.java:165) advised by afterReturning advice from 'com.example.MyAspect' (MyAspect.java) [with runtime test]
[ERROR] [AppClassLoader@2b193f2d] weaveinfo Join point 'method-execution(void com.example.MyAspectTest$MyTargetClass.myMethod(int))' in Type 'com.example.MyAspectTest$MyTargetClass.' (MyAspectTest.java:182) advised by afterReturning advice from 'com.example.MyAspect' (MyAspect.java) [with runtime test]
[INFO] Running com.example.MyAspectTest
[ERROR] Tests run: 5, Failures: 0, Errors: 5, Skipped: 0, Time elapsed: 0.055 s <<< FAILURE! - in com.example.MyAspectTest
[ERROR] com.example.MyAspectTest.testMyMethod  Time elapsed: 0.011 s  <<< ERROR!
java.lang.NoSuchMethodError: 'com.example.MyAspect com.example.MyAspect.aspectOf()'
    at com.example.MyAspectTest.<init>(MyAspectTest.java:57)

:MyAspect.java

package com.example;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {

    @AfterReturning("""
            @target(com.example.MyAnnotation)
            && (execution(* *.*(..)) || execution(* .new(..)))
            """)
    public void intercept(JoinPoint JoinPoint) throws Throwable {
        System.out.println("********** MyAspect intercepted");
    }
}

您的 aop.xml 中存在细微错误:

<include within="@com.example.MyAnnotation *" />

include within 规则太窄了。切面编织错误地仅限于目标 classes,切面 class 本身被排除在外,因为它本身不携带目标注释。效果是织布工 永远不会完成方面本身——记住,它不是由 AJC 编译的 前。这导致 NoSuchMethodError: ...MyAspect.aspectOf()。因此,将编织范围扩大到整个基础包可以解决您的问题:

<include within="com.example..*" />

还有两件事你应该改进:

  • 使用 @within 而不是 @target,因为 @target 是在运行时动态计算的。只有这样我们才能确定目标实例具有哪种确切类型。 @within 然而可以在静态评估 编织.
  • 使用 AspectJ 1.9.8.RC3 因为使用了 Java 17(您似乎喜欢新的文本块)。对于 LTW,只要字节码兼容,这可能不是绝对必要的,但最近尝试编译 Java 17 代码时,AspectJ 1.9.7 是不够的,因为它 最多只支持 Java 15.

这是我的 pull request 以及三个相应的提交。


更新: 如果出于任何原因你想避免在 aop.xml 中提及目标包,只需提及注释和方面,如下所示:

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
  <weaver options="-verbose -showWeaveInfo">
    <include within="com.example.MyAspect"/>
    <include within="@com.example.MyAnnotation *"/>
  </weaver>
  <aspects>
    <aspect name="com.example.MyAspect"/>
  </aspects>
</aspectj>

一种避免显式包含方面的方法是使用 AspectJ 编译器 AJC(例如通过 AspectJ Maven 插件)简单地编译方面库。


更新 2, 关于您的后续问题:如 AspectJ 1.9.7 release notes 中所述,由于 JEP 396,您需要将 --add-opens java.base/java.lang=ALL-UNNAMED 添加到您的Java 命令行。

我在 pull request #2 中解决了你的问题。