Gradle 8.0 新特性

Gradle 8.0 banner

Gradle 8.0 标志着 Gradle 在持续革新构建自动化和提升开发人员生产力方面的又一个重要里程碑。继 2021 年 5 月发布 Gradle 7.0 之后,我们致力于简化易用性,使执行常见任务变得轻而易举,让您能够专注于最大限度地提高生产力。

自 Gradle 7.0 以来,主要改进分为以下几类:

立即升级 以在您的构建中试用它们,或 使用 Gradle 启动新项目

如果您想及时了解 Gradle 的新功能和其他发展,请订阅 我们的新闻稿,并在 TwitterMastodon 上关注我们。

性能

缓慢的构建会产生不利影响,更快、更频繁地发布非常重要,尤其是对于像 Square 这样的大公司。随着每次 Gradle 版本的发布,我们的目标都是提高性能,确保每次迭代都超越其前身。

配置缓存

更快的配置时间

每个 Gradle 构建都有一个生命周期:初始化、配置和执行。许多性能特性都集中在执行阶段;但是,配置阶段可能很耗时。如果没有配置缓存,即使配置没有更改,也需要重复配置阶段。

为了改善这种情况,在 版本 6.6 中引入了名为 配置缓存 的实验性功能。这通过缓存结果并将其用于后续构建来降低配置阶段的成本。只有在项目配置方式发生更改时,才需要运行配置阶段。这是 Gradle 8.0 中的一个可选功能,它 为人们节省了大量时间。在 Gradle 8.1 中,配置缓存将变得稳定。

通过并行化实现更快的执行

使用 –parallel 标志并行运行任务已经可以提高构建时间。但是,同一项目中的任务不允许并行执行,除非它们专门编写为并行执行。启用 配置缓存 后,Gradle 可以实现更好的并行化。

启用配置缓存后,即使没有使用 –parallel 标志,Gradle 也会并行运行任务。所有任务都可以并行运行,即使是同一项目中的任务,因为配置缓存可以防止任务相互干扰配置。与配置缓存兼容的任务不需要进行更改以确保并行安全。

更快的 Java 编译

更快的增量编译

默认情况下,Gradle 使用 Java 增量编译器 来加快构建速度,方法是仅编译需要编译的 Java 源文件。增量编译已经存在了 5 年多,但一些用户开始在大型源代码集中遇到限制。

增量编译通过分析类之间的关系来工作。以前,这种分析仅在本地保存,并阻止 Gradle 在从 构建缓存 中命中缓存后立即执行增量编译。在具有大型源代码集的项目中,在缓存命中后重新编译所有源文件的成本抵消了缓存命中节省的时间。

增量分析现在保存在构建缓存中。因此,缓存命中后的编译将是增量的。

此外,增量编译分析的速度更快,并且比 Gradle 7.0 使用的内存更少。

这些更改的影响因项目而异,但可能非常大。在 Gradle 项目本身中,这些更改使增量编译速度提高了一倍!

对常量的更改不再触发完全重新编译

由于 Java 编译器的工作方式,以前的 Gradle 版本被迫在任何常量在上游依赖项中更改时执行完全重新编译。

Gradle 现在执行常量使用跟踪,并且仅重新编译使用已更改常量的类。

这可以加快包含许多常量的类的项目的增量构建速度,例如来自模板引擎的生成代码。

Java 编译在操作系统之间有更多缓存命中

Gradle 通过查看任务的输入来计算任务的缓存键。在不同的操作系统上签出源代码时,行尾可能会使任务的输入看起来不同,即使任务产生相同的输出。

Gradle 现在在编译 Java 代码时规范化源文件中的行尾,以在操作系统之间获得更好的缓存命中。

更灵敏的持续构建

持续构建 在输入发生变化时会自动重新执行带有请求任务的构建。这允许在开发过程中获得持续反馈。

由于最近一些 JDK 的实现细节,持续构建在 Java 9+ 上的 Windows 和 macOS 上通常效果不佳。检测更改并触发构建可能需要长达 10 秒的时间。

当使用新 Java 版本运行 Gradle 时,持续构建对 Windows 和 macOS 上的更改反应迅速。Gradle 现在使用其自身健壮且原生实现的文件系统监视系统,而不是依赖于 JDK 中的通用 API。

易用性

Java 工具链

您可能熟悉使用错误的 Java 版本并遇到构建失败的痛苦,但使用正确的供应商同样重要。 Java 工具链支持是在 Gradle 6.7 中引入的,允许您指定项目的 JDK。工具链自此成为执行此操作的最佳方式,在 7.x 线和 8.0 中继续得到支持。

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

Gradle 仍然可以 自动检测 安装的工具链,但我们通过 工具链解析器插件 提供了更高的配置灵活性。这为您提供了更大的灵活性,可以控制从哪里获取 JDK,以便您可以使用与您的需求相匹配的特定 JDK。

Build Scan™ 现在显示了 Java 工具链的使用情况

build scan image

测试套件

编写测试时的一个常见用例是将测试类分组以将其组织成可管理的块,以便您可以使用不同的频率或在构建管道的不同点运行它们。例如,您可能希望定义一组单元测试集成测试功能测试。正确执行此操作需要深入了解如何在 Gradle 中修改和连接各种领域对象,例如 SourceSets、配置和任务。

您会很高兴地知道,通过引入测试套件,这个过程已经得到了极大的简化。 JVM 测试套件插件 简化了创建这些被称为测试套件的测试组。 请注意,这与测试框架套件(如 JUnit4 的 SuiteJUnit Jupiter 的 Suite 引擎)不同。

测试套件是一个高级的声明式概念,可以在构建脚本中直接引用。 您可以在不担心底层细节的情况下配置依赖项、源代码和测试使用的测试框架。

例如,您可以通过将以下代码段添加到 Java 项目中来创建一个集成测试测试套件

testing {
  suites {
    // Add a new test suite
    integrationTest(JvmTestSuite) {
      // Use JUnit Jupiter as a testing framework
      useJUnitJupiter('5.7.1')

      // depend on the production code for tests
      dependencies {
        implementation project
      }
    }
  }
}

// Run integration tests as part of check
tasks.named('check') {
  dependsOn(testing.suites.integrationTest)
}

版本目录

Version catalog code

Gradle 在 7.0 版本中引入了版本目录作为实验性功能。 如果您还没有尝试过 版本目录 来管理您的依赖项,现在是时候进行切换了。 它用于在一个中心位置(文件 gradle/libs.versions.toml)中声明构建中使用的所有直接依赖项的版本。 一些优势包括类型安全访问、跨依赖项的通用版本控制以及将依赖项捆绑在一起。

在 7.x 系列和 8.0 中,版本目录 在许多方面得到了改进。 以下是一些具体的例子。

声明插件版本

版本目录已经支持声明库的版本。 但是,这些声明无法访问 pluginsbuildscript 块。 此限制已解除,现在可以声明插件,例如在 TOML 文件中

Version catalog code

在插件块中使用它们,如下所示

Plugin block code

版本目录类型不安全 API 更改

在使用类型不安全 API 时,所有接受 别名引用 的方法现在可以使用与别名定义相同的字符串。 这意味着您可以声明和引用 groovy-json,而不是被迫在类型不安全 API 中使用 groovy.json

请注意,对类型不安全 API 的访问已更改;请参阅 升级指南

Kotlin DSL

Gradle 的 Kotlin DSL 为传统的 Groovy DSL 提供了一种替代语法,在支持的 IDE 中提供了增强的编辑体验、卓越的内容辅助、重构、文档等。 为了确保 Kotlin 体验出色,我们付出了很多努力。

改进的脚本编译性能

在许多情况下,Kotlin 脚本编译传统上比 Groovy 脚本编译速度慢。 Gradle 8.0 通过为 .gradle.kts 脚本中的 声明式插件 {} 块 引入解释器,可以使 Kotlin 脚本编译速度提高高达 20%。 默认情况下,将避免为声明式 plugins {} 块调用 Kotlin 编译器。

要从这种性能改进中受益,请在 plugins {} 块中使用支持的格式。 有关插件语法的更多信息,请阅读有关 约束语法 的文档。

Kotlin DSL 中的 repositories {} 扩展的类型安全访问器

Kotlin DSL 为添加到 repositories {} 块中的自定义扩展生成 类型安全的模型访问器。自定义扩展在 IDE 中具有完整的代码提示功能。

例如,[asciidoctorj-gems-plugin](https://asciidoctor.github.io/asciidoctor-gradle-plugin/master/user-guide/#asciidoctorj-gems-plugin) 插件添加了一个自定义扩展。您不再需要 withGroovyBuilder,而是可以使用这种简洁的语法

Kotlin code

构建配置

多年来,构建配置发生了很多变化。当前的最佳实践有时是使用 buildSrc,有时是使用 包含构建。在规模上,包含构建有时性能更高,而有时 buildSrc 性能更高。性能取决于具体结构。但是,许多项目仍然使用应用脚本(缺乏 IDE 自动完成)甚至 allprojects/subprojects(难以确定共享配置来自哪里,并且不灵活且性能不佳)。

为了统一 buildSrc包含构建,buildSrc 正在改变以更像包含构建。请注意,这意味着 buildSrc 测试不会自动运行,您可以通过命令行像处理普通包含构建任务一样处理 buildSrc 任务。

BuildSrc

如果您已经在使用 buildSrc,请继续使用它并享受新功能。如果您已经在使用包含构建,请继续使用它们。如果您的构建性能需要改进,请尝试两种解决方案并为您的项目选择最佳组合。

生态系统支持升级

支持 Java 17 到 19

Gradle 支持在 Java 17、18 和 19 上编译、测试和运行。

支持 Groovy 4

Gradle 支持使用 Groovy 4.0 构建软件。请注意,Groovy DSL 构建脚本仍然使用 Groovy 3。

更新的 Scala 编译器

默认的 Scala Zinc 版本已 更新至 1.6.1

Zinc 是 Scala 增量编译器,它允许 Gradle 始终编译当前文件更改所需的最小文件集。它会考虑哪些方法正在使用以及哪些方法已更改,这意味着它比文件间依赖关系更细粒度。

Kotlin DSL 中的新 Kotlin 功能

使用 Kotlin DSL 编写的构建脚本使用 Kotlin API 级别 1.8。以前,构建脚本仅限于 Kotlin API 级别 1.4。此更改带来了自 Kotlin 1.4.0 以来对 Kotlin 语言和标准库的所有改进。

有关此升级中的重大更改和非重大更改的信息,请访问升级指南

如何升级

我们提供了一份文档来帮助您从 Gradle 7.x 升级到 Gradle 8.0。如果您使用的是比 Gradle 7.0 更早的版本,您可能需要先查看Gradle 7.0 中的所有新功能

升级之前,您应该

  • 使用 Gradle 包装器升级到 Gradle 7.6.1。 gradle wrapper --gradle-version=7.6.1
  • 运行 gradle help --scan 以列出所有使用过时的 Gradle API 及其位置
  • 更新您的 Gradle 插件,尤其是 Build Scan™ 中的弃用报告中列出的那些插件
  • 使用 Gradle 包装器升级到 Gradle 8.0.2。 gradle wrapper --gradle-version=8.0.2
  • 如果您遇到问题,请查看故障排除指南或联系社区论坛

您可以通过TwitterMastodon与 Gradle 团队分享反馈。开始构建幸福吧!