1. 概述

在这个教程中,我们将探讨Gradle工具链支持JVM项目的方法。我们将首先理解这个功能的动机,然后定义它,并通过实际示例进行演示。

2. 工具链背后的原因

在讨论什么是工具链之前,我们需要了解其存在的原因。假设我们要编写一个Java项目,它可能包含一些测试。因此,我们至少希望编译代码并运行测试。我们添加内置的java Gradle插件,并指定所需的字节码版本:

plugins {
    id 'java'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

此外,我们可以告诉Gradle根据需要将测试类编译成不同的字节码版本:

tasks {
    compileTestJava {
        sourceCompatibility = JavaVersion.VERSION_1_7
        targetCompatibility = JavaVersion.VERSION_1_7
    }
}

到目前为止,一切正常。唯一的微妙之处是,为了编译源代码/测试类,Gradle使用了自己的JDK,即它运行的JDK。不过,我们可以通过指定确切的可执行文件来解决这个问题:

compileTestJava.getOptions().setFork(true)
compileTestJava.getOptions().getForkOptions().setExecutable('/home/mpolivaha/.jdks/corretto-17.0.4.1/bin/javac')

compileJava.getOptions().setFork(true)
compileJava.getOptions().getForkOptions().setExecutable('/home/mpolivaha/.jdks/corretto-17.0.4.1/bin/javac')

然而,如果在构建过程中使用了各种JDK,问题就出现了。

例如,假设我们在发布前必须在客户的JDK上测试我们的Java应用。这些JDK可能来自不同的供应商,尽管符合规范,但在细节上可能会有所不同。理论上,我们可以不使用工具链解决这个问题,但解决方案会复杂得多。工具链使需要为不同目的使用不同JDK的构建配置更加简单。

3. 工具链定义

从Gradle 6.7版本开始,引入了JVM工具链功能。虽然工具链的概念并不新鲜,Maven已经存在一段时间了此处链接。一般来说,工具链是一组用于构建、测试和运行软件所需的工具和二进制文件。因此,在Java中,我们可以将JDK视为Java工具链,因为它允许编译、测试和运行Java程序。

我们可以在项目级别定义工具链,如下所示:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
        vendor = JvmVendorSpec.AMAZON
        implementation = JvmImplementation.VENDOR_SPECIFIC
    }
}

这样,我们可以指定所需的Java版本、JDK供应商以及该供应商特定的JVM实现。为了使工具链规范正确,至少需要设置版本.

当Gradle处理工具链时,它的行为很简单。首先,它会尝试在本地查找请求的工具链;这里有一个特定的算法。如果Gradle在本地找不到所需的工具链,它会尝试从远程查找并下载。如果Gradle无法在远程找到所需的工具链,构建就会失败。

值得一提的是,有时我们可能希望禁用自动提供。我们可以通过将\-Porg.gradle.java.installations.auto-download=false传递给gradle可执行文件来做到这一点。在这种情况下,如果工具链在本地找不到,Gradle构建将失败。

4. 在任务级别使用工具链

工具链的真正威力在于能够按任务方式指定JDK安装:

tasks.named('compileJava').get().configure {
    javaCompiler = javaToolchains.compilerFor {
        languageVersion = JavaLanguageVersion.of(17)
        vendor = JvmVendorSpec.AMAZON
        implementation = JvmImplementation.VENDOR_SPECIFIC
    }
}

tasks.register("testOnAmazonJdk", Test.class, {
    javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(17)
        vendor = JvmVendorSpec.AMAZON
    }
})

tasks.named("testClasses").get().finalizedBy("testOnAmazonJdk")

在上面的示例中,我们配置了compileJava任务在Oracle JDK 15上运行。我们还创建了一个名为testOnAmazonJdk的任务,它将在testClasses任务之后运行。请注意,这个新任务也在单独的JDK上执行。

5. 查看本地工具链

最后,Gradle允许我们使用以下命令查看当前项目可用的本地工具链安装:

gradle javaToolchains

首先,Gradle会在当前位置搜索构建文件,然后根据构建文件中指定的位置/规则列出找到的工具链。

6. 总结

在这篇简短的教程中,我们回顾了Gradle的工具链功能。如果适用,这个功能简化了在构建过程中使用不同JDK的工作。它从Gradle 6.7开始可用,并且我们可以在任务级别应用,这使得这个功能非常有价值。

如往常一样,本文的源代码可以在GitHub上找到。