Gradle 6.0 新特性

Gradle 6.0 是多年创新改进的结晶。观看我们的 Gradle 6.0 新特性网络研讨会录像

Gradle 6.0 中的依赖管理理念认为,软件组合和重用不仅仅是将一组 jar 文件放在类路径上。Gradle 现在提供了一种新的元数据格式,以丰富地定义软件组件,这些组件通常由多个文件、不同的变体以及对其依赖项的特定约束组成。

Gradle 6.0 将通过更新 Java、Groovy 和 Scala 生态系统插件来帮助提高您的整体开发者生产力。插件作者使用的 API 不断发展,使创建可并行化、可增量且易于使用的插件和任务变得更加容易。

com.gradle.build-scan 插件针对 Gradle 6.0 进行了重大更新。scans.gradle.comDevelocity 用户需要切换到 com.gradle.enterprise 插件。这不仅仅是具有新 ID 和新应用方式的相同插件。com.gradle.enterprise 插件可靠地捕获 buildSrc 构建事件和失败。

如果您有兴趣关注 Gradle 新功能的开发,当有新功能预览(例如 Swift 支持)或关于避免依赖地狱的建议时,我们会将更新发布到我们的博客。我们还发布了过去网络研讨会的视频,内容涉及顶级的 Android 构建问题、依赖管理技术和发布策略。

以下是 Gradle 5.0 到 6.0 的主要改进

使用 Gradle 模块元数据进行依赖管理

当使用 maven-publishivy-publish 插件时,Gradle 模块元数据的发布现在是默认设置。这使得许多创新的依赖管理功能(如下所述)可以在项目边界之间工作。

在项目之间使用平台共享依赖版本

Gradle 提供了一种简单的方法来推荐和共享版本,称为平台

借助 Gradle 平台,可以获得更多关于版本声明的上下文,可以推荐版本并强制执行严格版本。为了互操作性,构建还可以利用与 Maven BOM 的集成

处理互斥依赖

Gradle 使用能力来允许插件和构建检测和解决互斥依赖之间的实现冲突。JVM 世界中一个众所周知的例子是竞争的日志记录实现。能力让构建配置选择哪个依赖,而不是将竞争的依赖添加到类路径中。

升级传递依赖的版本

依赖管理问题通常是关于处理传递依赖。通常,传递依赖问题通过添加直接依赖来错误地修复。为了避免这种情况,Gradle 提供了依赖约束的概念,以影响传递依赖的版本。

对齐多个依赖之间的版本

依赖版本对齐允许构建表达不同的模块属于同一个逻辑组(如平台),并且需要在依赖图中具有相同的(又名对齐的)版本。JVM 世界中一个众所周知的例子是 Jackson 库。

使用上下文表达意图

当声明依赖时,构建可以向 Gradle 提供更多关于其版本的上下文,包括范围内的版本偏好、严格的版本要求或拒绝的版本。开发者还可以为为什么使用或需要依赖项提供人类可读的描述。

调整发布的元数据

Gradle 允许构建修复或丰富传统元数据,其中包含以前无法发布的信息,例如依赖约束、丰富版本、能力和变体。这些被称为组件元数据规则。组件元数据规则还可以将额外的已发布工件映射到新的 Gradle 变体。

建模功能变体和可选依赖

Gradle 提供了建模库的可选功能的能力。每个功能变体都可以有自己的一组依赖项,并且可以单独使用。

为 Java、Groovy 和 Scala 开发者提供更好的构建

您可以通过升级到 Gradle 6.0 来改进您的 Java、Groovy 或 Scala 构建。

更快的 Java 增量编译

当分析更改的类的影响时,增量编译器现在可以排除作为另一个类的实现细节的类。这限制了需要重新编译的类的数量。对于深度依赖链,这大大减少了需要重新编译的文件数量。

例如,在更改单个源文件后编译一个包含 5000 个源文件的项目

Gradle 5.6 ( 21s)
Gradle 5.6 需要 21 秒才能编译。
Gradle 6.0 (0.5s)
Gradle 6.0 只需要 0.5 秒即可编译相同的更改。

更快的 Groovy 编译

Gradle 6.0 通过两种策略加速 Groovy 编译。

Gradle 使用编译避免来跳过重新编译依赖项目,如果没有任何更改会影响其编译输出。

Gradle 还使用增量 Groovy 编译。如果只更改了少量 Groovy 源文件,则只会重新编译受影响的源文件。例如,如果您只更改了一个 Groovy 测试类,Gradle 不需要重新编译所有 Groovy 测试源文件。Gradle 将仅重新编译更改的类和受其影响的类。

使 Java 增量编译更快的相同分析改进也适用于 Groovy 编译。

此功能需要更改您的构建才能使用。请参阅 Groovy 编译避免Groovy 增量编译 以了解更多详情。

最新的 Zinc 编译器集成

Gradle 6.0 使用最新的 Zinc 增量 Scala 编译器。Zinc 编译器在 Zinc 1.0 中看到了主要的性能改进。

默认情况下,Gradle 使用 Zinc 1.3.0。

支持广泛的 JDK

Gradle 6.0 现在支持 Java 13

Gradle 支持在 JDK8 到 JDK13 上运行。JDK6 和 7 仍然可以用于编译和测试。

添加 Javadoc 和 sources jars

您现在可以为 Java Library 或 Java 项目激活 Javadoc 和 sources 发布

java {
    withJavadocJar()
    withSourcesJar()
}

使用 maven-publishivy-publish 插件,这不仅会自动创建和发布 -javadoc.jar 和 -sources.jar,还会发布这些存在作为 Gradle 模块元数据中的变体的信息。这意味着您可以查询模块的 Javadoc 或 sources 变体,还可以检索其依赖项的 Javadoc(或 sources)。

如果激活,Java 和 Java Library 项目会自动提供 javadocJar 和 sourcesJar 任务。

在项目之间共享测试 fixtures

Gradle 6.0 允许在一个项目中的 Java 测试 fixtures 与构建中的其他项目共享。Gradle 将自动执行必要的连接,以便测试编译依赖于测试 fixtures。java-test-fixtures 插件需要与 java-library 插件一起应用。它也可以与其他 JVM 语言插件(如 Groovy 或 Scala)结合使用,以使用这些语言编写测试 fixtures。

例如,这会将 “my-lib” 的测试 fixtures 添加到项目中的测试的编译类路径中。

dependencies {
   testImplementation(testFixtures(project(":my-lib")))
}

组织您的构建逻辑

Gradle 6.0 帮助您控制构建。

通过自定义分发 gradle.properties 实现组织范围的 Gradle 属性

Gradle 现在会在构建使用的 Gradle 分发版中查找 gradle.properties 文件。此文件具有任何 gradle.properties 的最低优先级,并且在其他位置定义的属性将覆盖此处定义的值。

通过将 gradle.properties 文件放置在自定义 Gradle 分发版中,组织可以为整个组织添加默认属性,或者使用 org.gradle.jvmargs 调整默认的 Gradle 守护进程内存参数。

从 settings.gradle 集中管理插件版本

Gradle 6.0 使管理构建使用的插件版本变得更加容易。通过在新 pluginManagement.plugins {} 块内的 settings 脚本中配置所有插件版本,构建脚本可以通过 plugins {} 块应用插件,而无需指定版本。

pluginManagement {
    plugins {
        id 'org.my.plugin' version '1.1'
    }
}

以这种方式管理插件版本的一个好处是,插件版本可以从 gradle.properties 加载或以编程方式定义。

使用 Composite Builds 进行插件开发

构建脚本中的 plugins { } 块现在可以用于引用在包含的构建中定义的插件。在以前版本的 Gradle 中,这是可能的,但需要在 settings 文件中添加一些额外的样板代码。现在不再需要此样板。

此更改使得为 Gradle 插件添加测试构建变得非常容易,并简化了实现 Gradle 插件的过程。您还可以使用此功能方便地处理插件和使用该插件的构建的更改,以实现一个插件,该插件既可以发布又可以被同一源代码存储库中的项目使用,或者将复杂的构建结构化为多个插件。

使用 plugins { } 块也使得 Gradle Kotlin DSL 更加方便易用。

您可以在用户手册中找到更多关于复合构建的信息。

用于更好插件的 API

Gradle 6.0 使您更容易构建快速且行为正确的插件。

最大限度地减少任务需要完成的工作量

使用 Gradle,实现一个任务非常简单,当其所有输入和输出都是最新的时,该任务将被跳过。这允许 Gradle 执行增量构建,其中仅执行需要执行的任务。

对于某些任务,即使任务需要执行,也可以减少工作量。如果自上次执行以来仅更改了少量输入文件,则任务只需要重新处理已更改的文件。Gradle 将这些类型的任务称为增量任务。要实现增量任务,请使用 InputChanges API

使工作并行安全

Gradle 6.0 有一个新的 API,任务可以使用它来提交要并行执行的工作单元。选择加入此 API 的任务使 Gradle 能够更灵活地并行启动其他任务。

使用此 API 的插件作者可以将任务的操作移动到单独的类加载器甚至单独的进程中。单独的进程在可能的情况下会被重用,如果它们消耗过多资源则会过期。单独的类加载器允许插件非常灵活地控制任务操作使用的类路径。

工作单元的参数是类型安全的和隔离的,因此它们不能与工作单元的操作并发修改。参数可以是可选的 (null) 或由复杂类型(例如,文件集合)组成。有几个服务可以注入到操作中以执行常见功能,例如复制和删除文件或派生其他进程。

验证任务配置

任务不正确地定义其输入或输出可能会在运行增量构建或使用构建缓存时导致问题。作为正在进行的努力的一部分,为了揭示这些问题,Gradle 6.0 现在在构建期间将这些问题报告为弃用警告

当检测到问题时,当使用 --warning-mode=all 运行时,Gradle 将显示警告

> Task :myTask
Property 'inputDirectory' is declared without normalization specified. 
Properties of cacheable work must declare their normalization via @PathSensitive, @Classpath or @CompileClasspath. 
Defaulting to PathSensitivity.ABSOLUTE. This behaviour has been deprecated and is scheduled to be removed in Gradle 7.0.

Property 'outputFile' is not annotated with an input or output annotation. This behaviour has been deprecated and is scheduled to be removed in Gradle 7.0.

无论使用什么命令行参数,弃用警告始终会在Build Scan™ 中显示。

转换来自依赖项的工件

依赖项的工件可以采用多种形式 - JAR、AAR、ZIP 和其他格式。您甚至可能需要您正在使用的库未发布的格式。

例如,以发布普通 JAR 文件的 Java 模块为例。作为消费者,您想使用普通的 JAR 进行开发,但您需要使用混淆的 JAR 进行生产构建。

由于混淆的 JAR 在任何存储库中都不可用,因此您必须使用普通的 JAR 并自行混淆它。

Gradle 提供了一个 API 用于注册工件转换,该 API 挂钩到依赖管理解析引擎。工件转换可以指定,只要请求混淆的 JAR 但找不到,Gradle 就应该运行转换以创建混淆的 JAR 并使其显示为可用的工件。

您可能错过的其他内容

自 Gradle 5.0 以来发生了很多变化。以下是您可以在 Gradle 6.0 中享受的其他一些功能。

使用 gradle init 引导新项目

Gradle 6.0 可以使用 gradle init 和一些参数来引导项目。

您可以选择以下项目之一

  • 用 Java、Groovy、Kotlin、C++ 或 Swift 编写的应用程序
  • 用 Java、Groovy、Scala、Kotlin、C++ 或 Swift 编写的库
  • 用 Java、Groovy 或 Kotlin 编写的 Gradle 插件
  • 基本的空项目

通过按组过滤快速找到您想要运行的任务

Gradle 6.0 允许您通过仅显示属于特定组的任务来快速查找任务。这使得在具有许多可用任务的构建中更容易找到任务。

使用 gradle tasks --group="Build Setup" 试用。

通过在弃用警告时失败来保持最新

warning-mode 命令行选项有一个 fail 选项,该选项将显示所有弃用警告,并且如果在构建期间发现任何弃用警告,则构建将失败。

增量 PMD 分析

Gradle 6.0 的 PMD 插件支持使用 PMD 的增量分析缓存来提高构建之间文件未更改时的性能。要启用增量分析,请将以下内容添加到您的 PMD 配置中

pmd {
    incrementalAnalysis = true
}

执行具有长类路径的 Java 应用程序

当 Gradle 检测到 Java 进程命令行将超过 Windows 的 32,768 个字符限制时,Gradle 将尝试通过传递 Java 应用程序的类路径(通过“类路径 jar”)来缩短命令行。

类路径 jar 包含一个清单,其中包含应用程序的完整类路径。Gradle 将仅将生成的 jar 传递到应用程序的命令行。如果命令行仍然太长,Java 进程将像以前一样启动失败。

如果命令行不需要缩短,Gradle 将不会更改 Java 进程的命令行参数。

工件签名

Gradle 6.0 有几个与签名相关的改进

如果您使用 maven-publishivy-publish 插件,Gradle 除了传统的但不安全的 MD5 和 SHA1 签名外,还会自动上传 SHA256 和 SHA512 签名。

不推荐使用的 maven 插件不支持发布 SHA256 和 SHA512 文件,但适用于 Ivy 存储库的旧版 uploadArchives 任务。

如何升级

我们提供了一份文档,以帮助您从 Gradle 5.x 升级到 Gradle 6.0。如果您使用的是比 Gradle 5.0 更旧的版本,您可能需要先查看Gradle 5.0 中的所有新特性

在升级之前,我们建议您

  • 使用 Gradle Wrapper 升级到 Gradle 5.6.4。gradle wrapper --gradle-version=5.6.4
  • 运行 gradle help --scan 以列出所有已弃用的 Gradle API 及其位置的使用情况。
  • 更新您的 Gradle 插件,尤其是 Build Scan™ 的弃用报告中列出的插件。
  • 如果您遇到困难,请参阅故障排除指南或在社区论坛上寻求帮助。

您可以通过 @gradle on Twitter 与 Gradle 团队分享反馈。前进并构建快乐!