簡體   English   中英

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

[英]How to make an AspectJ Aspect work in a Gradle project?

我正在使用以下示例代碼來理解 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);
    }
}

和以下方面:

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);
    }
}

我正在使用以下 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")
}

我在 Intellij 中使用 Ajc 編譯器來編譯 Java 類和方面。 此外,我正在設置以下 VM 選項:

-javaagent:c:\\Users\\dev\\extlibs\\aspectjweaver-1.9.6.jar

代碼編譯並運行沒有任何問題,但方面永遠不會觸發。 我不確定我的配置中缺少什么,但是在使用 AspectJ 時我找不到其他可以做的事情。 如果我使用@Aspect 注釋並在 META-INF/aop.xml 中注冊帶注釋的方面,則方面會運行,但帶注釋的@Aspect Java 類不允許創建我需要捕獲/攔截私有方法的特權方面。 有關如何解決此問題的任何建議?

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

  • Freefair post-compile-time weaving plugin:這是不必要的,因為你有 Java 源代碼,並且可以使用普通的compile-time weaving將它與aspect一起編譯。
  • AspectJ Maven 插件:這是沒用的,因為您不能簡單地在 Gradle 中使用 Maven 插件。
  • AspectJ 加載時編織 Java 代理:這是不必要的,因為就像我說的,您可以在這里使用正常的編譯時編織。 如果您不使用-javaagent: ,您也不需要aop.xml

我想你可以使用所有三個選項,編譯時、編譯后時間和加載時編織,但你應該決定哪一個而不是混合它們。 您還應該決定是否要使用 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"
}
  1. 現在,當從我的 IDE 運行主要 class 時,我看到如下內容:
> 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

當然,您也可以編譯一個單獨的方面庫並將其編織到您的應用程序代碼中,如果要為多個應用程序或模塊重新使用方面庫,或者如果應用程序源代碼不是在 Java 中編寫的(但例如在 Kotlin 中, Groovy 或 Scala),因此不能由 AspectJ 編譯器直接編譯。 不過,我不會在這里討論這個,因為我想向您展示最簡單的解決方案,因為您似乎是初學者。 (順便說一句,我也不是 Gradle 用戶,我通常將 AspectJ 與 Maven 一起使用。)


更新:插件文檔確實很糟糕,但是您可以在維護者的 GitHub 存儲庫中看到一些示例項目

  • 方面:編譯時編織,即一個模塊中的應用程序+方面,如我的回答中所示
  • httpcore-nio:編譯后編入第三方庫
  • 測試:如何測試方面
  • 編織: Java、Groovy 和 Lombok 中的混合語言方面以及如何在單個模塊中一起使用它們

所有這些也可以使用 Maven 和 AspectJ Maven 插件來完成,但您特別要求 Gradle。

感謝這個線程中的指針,我能夠從 Gradle 成功構建 2 種寫作方面 -

  1. 在 src/main/java 中定義的方面 - https://github.com/vadakr/gradle-aspect-inside-java
  2. 在 src/main/java 之外定義的方面,例如在 src/main/aspectj - https://github.com/vadakr/gradle-aspect-outside-java

請注意,我使用了 'io.freefair.aspectj.post-compile-weaving' Gradle 插件( https://docs.freefair.io/gradle-plugins/6.0.0-m2/reference/#_io_freefair_aspectj )最簡單的方法是它自動將 Java 類(所有可能的連接點)傳遞到“ajc”中——您需要做的就是將其指向方面本身。

在調試 Gradle 構建過程時,查看生成的ajc 選項被證明是非常有用的。 將這些與https://www.eclipse.org/aspectj/doc/next/devguide/ajc-ref.html進行交叉檢查通常是問題的根源。 它通常與 -inpath 或 -sourceroots 相關。

  • -inpath 是您將連接點放入“ajc”的方式
  • -sourceroots 是您將方面(切入點/建議)納入“ajc”的方式

請注意,屏幕截圖來自 IntelliJ。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM