介绍 Java 工具链

构建 Java 项目和运行 Gradle 都需要安装 JDK。大多数 Gradle 用户方便地使用运行 Gradle 的 Java 安装来构建和测试他们的应用程序。

虽然这在简单情况下是可以接受的,但这种方法存在一些问题。例如,如果构建需要在所有机器上使用相同的 Java 版本,则每个开发人员都需要了解该要求并手动安装该版本。

以前可以配置 Gradle 使用与运行 Gradle 的 Java 版本不同的 Java 版本构建项目。但是,这需要分别配置每个任务,例如编译、测试和 javadoc。

Gradle 6.7 引入了“Java 工具链支持”。简而言之,它允许您使用已安装的任何版本的 Java 运行 Gradle,而 Gradle 使用在单个位置声明的 Java 版本构建项目。Gradle 将自动配置构建,检测已安装的 JDK,并在尚未安装的情况下下载所需的 JDK。

不再需要 releasesourceCompatibility 调整,也不再需要描述应安装哪个 JDK 才能使构建正常工作的维基页面。优势是巨大的,让我们看看如何使用它!

介绍 Java 工具链支持

Java 工具链支持允许构建作者声明他们的项目需要哪个 Java 版本来编译、测试和运行他们的代码。

项目范围配置

让我们从构建作者至少需要做的事情开始

plugins {
    id("java-library") // or id("application")
}

java {
    toolchain {
            languageVersion.set(JavaLanguageVersion.of(11))
    }
}

就是这样!

在 Gradle 6.7 中,上述配置能带来什么?

你会得到

  • 所有 Java 编译任务将使用 Java 11 进行构建。这意味着 maintest 源集中的代码,以及您添加的任何自定义源集中的 Java 代码,都将使用配置的 Java 版本进行构建。
  • 所有测试任务,包括默认的 test 任务和任何其他自定义 Test 任务,都将使用 Java 11 运行测试。
  • javadoc 任务将使用 Java 11 构建文档。

此外,使用 application 插件,run 任务将使用 Java 11 启动您的应用程序。

在幕后,Gradle 将

如果 Gradle 无法找到所需的 Java 版本,您可以告诉它 在哪里查找

任务级别配置

在某些情况下,您需要为特定任务使用不同的工具链。假设您开发的库具有取决于其运行的 Java 版本的特定代码路径。您需要确保两个代码路径都被执行,因此将使用不同的 Java 版本运行一组测试。此场景支持如下。

tasks.register<Test>("extraTests") {
    javaLauncher.set(javaToolchains.launcherFor {
        languageVersion.set(JavaLanguageVersion.of(14))
    })
}

前往 文档 了解更多信息。

使用工具链的更多好处

除了我们之前讨论过的优势外,工具链还可以帮助解决更多情况。

Gradle 在构建尚未发布的 Java 版本(例如本文撰写时的 Java 16)的代码时存在问题,这可能会导致现有 Gradle 版本(例如当前的 6.7 版本)无法运行。

借助工具链支持,Gradle 6.7 能够完美地使用尚未发布的语言版本编译和测试代码。您只需要告诉它这样做即可。

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(16))
    }
}

此外,代码在使用不同的 Java 版本构建和运行时可能会表现出不同的行为,这可能会导致难以诊断的问题。

即使没有影响系统行为的不兼容性,在不同机器上使用不同的 Java 版本构建项目也会降低构建性能,因为 构建缓存 丢失。

放宽 Gradle 上的 Java 版本约束

除了对构建作者的好处外,此功能还将对 Gradle 本身的开发产生影响。到目前为止,Gradle 假设它将使用与项目所需的相同版本的 Java 运行。这意味着 Gradle 必须能够使用一组跨越使用 Gradle 的项目的需要的 Java 版本运行。在 Java 5 到 8 的发布节奏中,这可能是可以接受的。随着新的 Java 发布计划,这将更加成问题。

从 6.7 版本开始,Gradle 需要

  • 至少 Java 8 才能运行构建,
  • 每天使用 11 构建
  • 并测试到 Java 15。

所有这些都需要相当复杂的 CI 设置,并对 Gradle 核心开发施加了限制。例如,Gradle 工程师无法访问 Java 8 以外的功能和 API 来开发该工具。

一旦工具链在社区中被采用,我们最终将能够在 Gradle 的运行时要求方面不那么保守。Gradle 然后可能只在相对较新的 Java 版本上运行,同时通过工具链支持构建旧版 Java 版本的代码。

工具链的下一步是什么?

在 Gradle 6.7 中,工具链支持仅限于 Java 专用插件已知的任务

  • JavaCompile
  • Test
  • Javadoc
  • JavaExec

计划在下一个 Gradle 版本中添加对 Groovy 和 Scala 插件的工具链支持。

我们还希望,鉴于此功能对用户的益处,社区 插件作者将在他们自己的任务中利用工具链支持

讨论