如何使 AspectJ Aspect 在 Gradle 项目中工作?

F. *_* K. 4 java aspectj gradle aspect

我正在使用以下示例代码来理解 AspectJ:

public class Account {
    int balance = 20;

    public boolean withdraw(int amount) {
        if (balance < amount) {
            return false;
        }
        balance = balance - amount;
        return true;
    }

    public static void main(String[] args) {
        Account acc = new Account();
        acc.withdraw(5);

        Account acc2 = new Account();
        acc2.withdraw(25);
    }
}
Run Code Online (Sandbox Code Playgroud)

以及以下方面:

public aspect AccountAspect {

    pointcut callWithDraw(int amount, Account acc) :
            call(boolean Account.withdraw(int)) && args(amount) && target(acc);

    before(int amount, Account acc) : callWithDraw(amount, acc) {
        System.out.printf("[before] withDraw, current balance %d%n", acc.balance);
    }

    boolean around(int amount, Account acc) : callWithDraw(amount, acc) {
        if (acc.balance < amount) {
            System.out.println("[around] withDraw, check failed");
            return false;
        }
        System.out.println("[around] withDraw, check success");
        return proceed(amount, acc);
    }

    after(int amount, Account acc) : callWithDraw(amount, acc) {
        System.out.printf("[after] withDraw, current balance %d%n", acc.balance);
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用以下 Gradle 构建文件:

plugins {
    id 'java'
    id "io.freefair.aspectj.post-compile-weaving" version "4.1.4"
}

configurations {
    ajc
    aspects
    aspectCompile
    compile{
        extendsFrom aspects
    }
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation group: 'org.aspectj', name: 'aspectjrt', version: '1.9.4'
    implementation group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.4'
    implementation group: 'org.codehaus.mojo', name: 'aspectj-maven-plugin', version: '1.8'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}
compileJava {
    sourceCompatibility = "1.8"
    targetCompatibility = "1.8"
    //The following two lines are useful if you have queryDSL if not ignore
    dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
}
Run Code Online (Sandbox Code Playgroud)

我在 Intellij 中使用 Ajc 编译器来编译 Java 类和方面。此外,我正在设置以下 VM 选项:

-javaagent:c:\\Users\\dev\\extlibs\\aspectjweaver-1.9.6.jar
Run Code Online (Sandbox Code Playgroud)

代码编译和运行没有任何问题,但方面永远不会触发。我不确定我的配置中缺少什么,但是在使用 AspectJ 时我找不到我可以做的任何其他事情。如果我使用@Aspect 批注并在 META-INF/aop.xml 中注册带批注的 Aspect,则该方面会运行,但带批注的 @Aspect Java 类不允许创建我需要捕获/拦截私有方法的特权方面。有关如何解决此问题的任何建议?

kri*_*aex 5

你在那里混合了很多东西:

  • Freefair 编译后编织插件:这是不必要的,因为您有 Java 源代码并且可以使用正常的编译时编织将它与方面一起编译。
  • AspectJ Maven 插件:这是无用的,因为您不能简单地在 Gradle 中使用 Maven 插件。
  • AspectJ 加载时编织 Java 代理:这是不必要的,因为正如我所说,您可以在这里使用正常的编译时编织。你也不需要aop.xml文件,如果你不使用-javaagent:

我想你可以使用所有三个选项,编译时、编译后和加载时编织,但你应该决定哪一个而不是混合它们。您还应该决定是要使用 Gradle 还是 Maven,也不要尝试混合使用它们。

这是编译时编织的工作方式:

  1. 将应用程序和方面代码都放在目录中src/main/aspectj
  2. 将您的 Gradle 构建文件简化为:
plugins {
  id "java"
  id "io.freefair.aspectj" version "5.1.1"
}

group "org.example"
version "1.0-SNAPSHOT"

repositories {
  mavenCentral()
}

dependencies {
  implementation "org.aspectj:aspectjrt:1.9.6"
}
Run Code Online (Sandbox Code Playgroud)
  1. 现在,当从我的 IDE 运行主类时,我看到如下内容:
> Task :compileJava NO-SOURCE
> Task :compileAspectj UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE

> Task :Account.main()
[before] withDraw, current balance 20
[around] withDraw, check success
[after] withDraw, current balance 15
[before] withDraw, current balance 20
[around] withDraw, check failed
[after] withDraw, current balance 20
Run Code Online (Sandbox Code Playgroud)

当然,您也可以编译一个单独的方面库并将其编织到您的应用程序代码中,如果方面库要为多个应用程序或模块重用,或者如果应用程序源代码不是用 Java 编写的(例如在 Kotlin 中, Groovy 或 Scala),因此不能由 AspectJ 编译器直接编译。不过,我不会在这里讨论这个,因为我想向您展示最简单的解决方案,因为您似乎是一个初学者。(顺便说一句,我也不是 Gradle 用户,我通常将 AspectJ 与 Maven 一起使用。)


更新:插件文档非常糟糕,但您可以在维护者的 GitHub 存储库中看到一些示例项目

  • 方面:编译时编织,即一个模块中的应用程序+方面,如我的回答中所示
  • httpcore-nio:编译后编入第 3 方库
  • 测试:如何测试方面
  • weaving: Java、Groovy 和 Lombok 中的混合语言方面以及如何在单个模块中一起使用它们

所有这些也可以使用 Maven 和 AspectJ Maven 插件来完成,但您特别要求 Gradle。

  • Kriegaex,我现在明白为什么你说,这必须在 src/main/aspectj 中,因为这是 freefair 插件查找方面的默认位置。我可以通过在 build.gradle 中设置以下属性来使其在 src/main/java 中工作: sourceSets.main.aspectj.srcDir "src/main/java" sourceSets.main.java.srcDirs = files() 谢谢非常感谢你的帮助。 (2认同)