Gradle 7.0的发布已经一段时间了,我们来看下从Gradle 6.0到7.0,都有哪些有趣的特性。
- 加快增量编译速度
- 通过验证构建依赖项的完整性,使您的构建更安全。
- 支持使用
Java 16开发 - 使用
included builds简化构建 - 通过新的依赖管理特性降低了
Multi-Project构建的维护成本 - 使用最新版本的
Groovy和Kotlin开发
性能方面的优化
更快的up-to-date检查
本地增量编译的快速反馈对于提高开发效率至关重要。文件系统监视通过减少判断哪些文件发生了变化的IO操作,来提高增量编译速度
截至Gradle 7.0,在包括最近版本的Windows,Linux和MacOS的所有支持的操作系统上,默认情况下启用此优化。
关于文件系统监视的更多细节与原理,可参见:Introducing file system watching
加快kotlin DSL脚本编译速度
Gradle 7.0可以以更快的速度,更小的内存编译Kotlin DSL构建脚本,即KTS
此前当我们修改buildsrc中的代码时,会使大多数缓存失效,从而触发完全的重新编译
而在Gradle 7.0之后,修改buildsrc中的kts插件可以完全跳过未受影响的构建脚本文件的编译。
因此当修改buildsrc时,在Gradle7.0中,kts插件编译会远比gradle插件要快
提高build cache命中率
Gradle7.0通过有选择的忽略不会影响系统行为的一些更改,从而提高build cache的命中率
例如空的文件目录,属性文件中的空格和注释等,这些更改都会被忽略
支持configuration cache(实验性质)
Gradle已经支持了build cache,但是在执行任何Task之前,Gradle需要经过configuration阶段。目前configuration在每次构建时都会执行,并且可能导致明显的延迟,特别是在大型项目中。
configuration cache通过缓存configuration阶段的结果来提高构建性能。使用configuration cache,当没有影响configuration的更改时,Gradle可以完全跳过configuration阶段,以加快构建速度。
此外,使用configuration cache时,更多的工作是并行执行的,也可以加速构建的execution阶段。
请注意,此功能目前是实验性的,默认情况下未启用,并且自 Gradle 7.0 起也并非所有核心插件都支持。
关于configuration cache的更多细节与原理,可参见:Configuration cache
更快的临时构建速度
有时我们会进行一些临时的构建,临时构建机器需要重新下载所有依赖,这会付出比较大的代价。 Gradle 7.0可以通过跨机器重用dependency cache来加快临时构建的速度。
重定向dependency cache
dependency cache的默认位置为:$GRADLE_HOME/caches/modules-2,缓存目录可以重新定位到另一个目录或主机以缓存依赖项。
当重定向到新位置或新主机时,如果已下载依赖项,则使用dependency cache的构建将不需要访问网络来下载依赖
值得注意的是,应该使用兼容的 Gradle 版本来创建和使用缓存。可以浏览文档以了解更多细节
共享只读的dependency cache
Gradle提供了在多个Gradle实例之间共享dependency cache的能力。
这使得我们可以创建一个共享目录,其中包含所有构建所需的依赖项。
- 每个
Gradle实例都可以访问共享只读依赖性缓存,这避免了构建之间的冗余下载。 - 可以在
Gradle实例之间安全地共享此高速缓存,而无需创建其单独的副本。
易用性与新特性优化
JVM项目的工具链支持
默认情况下,Gradle使用相同的Java版本来运行Gradle本身并构建JVM项目,但这并不总是适用的。
在不同的开发机和 CI 服务器上构建,可能会使用不同的Java版本,这可能会导致预料之外的问题。此外,您可能希望使用与运行 Gradle 不兼容的 Java 版本来构建项目。
Gradle 提供了可以设置项目构建的Java版本的工具链:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(14)
}
}
Gradle将检查本地Java的安装情况,如果本地没有与构建要求匹配的 Java 版本,Gradle 将从 AdoptOpenJDK 的网站下载匹配的 JDK。
关于JVM项目工具链支持的具体使用,可参见:Toolchains for JVM projects
处理用户凭据
构建有时需要用户提供凭据。 例如,为了发布aar,Maven库可能需要身份验证,而将凭据保存在构建脚本之外是一种很好的做法。
Gradle 提供了一个 API,提供了一个 Gradle 属性来提供凭据,方便我们更轻松地使用凭据,这些属性可以作为命令行参数、环境变量或 gradle.properties 文件中的键值对,然后在构建脚本中可以读取这些值。 当 Gradle 知道构建在某些时候需要凭据并且缺少凭据时,它还会引入快速失败行为。
关于Gradle用户凭据的使用示例,可参考:Publishing Credentials Sample
支持执行included builds中的task
Gradle 允许用户直接从命令行从 included builds中执行Task。 例如,如果您的构建included build了 my-other-project,并且它有一个带有Task foo的子项目 sub,那么您可以使用以下命令执行 foo:
gradle :my-other-project:sub:foo
依赖锁定文件只保留一个
依赖锁定是一种在使用动态依赖版本时确保可重现构建的机制。Gradle 7.0 使用单个锁定文件将动态依赖项锁定到其解析的版本。而以前版本的 Gradle 每个Configuration使用一个文件, 在Gradle7.0中 会自动迁移到单锁文件。
安全性优化
依赖验证
我们的项目中常常会使用大量外部依赖项,这使他们面临使用不受信任代码的风险。 例如,有人可能会通过传递依赖意外引入恶意代码。同样,您的构建脚本本身也可能通过执行被感染插件的恶意代码,从而受到攻击。
为了减轻这些风险,Gradle 提供了依赖关系验证。 依赖项验证可以验证校验和以及构建期间使用的依赖项和插件的签名。
如果启用依赖项验证,Gradle 将:
- 确保依赖项没有被篡改(通过验证它们的校验和)
- 确保您使用的依赖项和插件的出处(通过验证它们的签名)
- 从而降低将恶意代码发送到生产环境的风险。
关于依赖验证的更多细节和使用,可以参见:Verifying dependencies
声明专有存储库依赖
Gradle 允许您声明应在哪些存储库中搜索特定依赖项。
Gradle 还允许您声明只能在一个存储库中找到且不应在任何其他存储库中搜索的专有依赖。
关于存储库专有依赖的具体细节,可以参见:user manual
验证 Gradle Wrappers 的完整性
Gradle Wrapper 是一个可执行代码的二进制文件,在数百万个 GitHub 存储库中使用。如果这个文件发生改变,可能存在一定的安全隐患
我们创建了一个官方 GitHub Action,它允许 GitHub 上的项目自动验证其存储库中的 gradle-wrapper.jar 是否由 Gradle 发布。
当然,你也可以通过user manual中的步骤,手动检验Gradle Wrapper文件的合法性
依赖管理
依赖解析一致性
configurations之间的依赖关系是独立解析的。这可能会导致一个问题,即测试的运行时classpath可能使用与生产代码的运行时classpath不同的版本。
为了缓解这个问题,Gradle 允许您声明依赖项configurations之间的一致性,以便保证两个classpath的公共依赖项的版本是一致的。
存储库统一声明
此前我们一般是在根目录的build.gradle中声明存储库,现在也可以在 settings.gradle (.kts) 中方便地为整个构建定义存储库:
dependencyResolutionManagement {
repositories {
mavenCentral ()
}
}
这允许 Gradle 确保您使用相同的存储库来解决构建的所有项目中的依赖关系。 了解更多,可以参考如何为整个构建声明存储库
组件元数据规则的统一声明
从存储库中提取的每个模块都有与之关联的元数据,例如其组、名称、版本以及它提供的不同变体及其工件和依赖项。有时元数据不完整或不正确。为了在构建脚本中操作这些不完整的元数据,Gradle 提供了一个 API 来编写组件元数据规则。 这些规则在模块的元数据下载后,并且在用于依赖解析之前生效。
dependencyResolutionManagement {
components {
withModule ('com.google.guava: guava', GuavaRule)
}
}
关于组件元数据规则统一声明的具体细节,可参见:Fixing metadata with component metadata rules
依赖统一管理的新特性
我们有多种方法可以在多项目构建中的项目之间共享依赖版本。 例如,用户可以直接在构建脚本的ext 块、外部文件(例如 dependencies.gradle)、buildSrc 甚至专用插件中声明版本或依赖坐标。 然而,没有任何标准机制可以结合每种方法的优点来做到这一点。
Gradle 引入了Version Catalog,使构建者能够将其第三方依赖项的依赖坐标(组、工件、版本)集中在常规配置文件中,并以类型安全的方式声明实际依赖项。
关于Version Catalog的具体使用,之前也写过一篇介绍,感兴趣的同学可以参见:【Gradle7.0】依赖统一管理的全新方式,了解一下~
类型安全的Project访问器
Gradle 为类型安全的Project访问器提供了一个实验性功能,它可以在 IDE 中完成代码自动补全地声明对其它Project的依赖
这比较大地解决了我们此前添加依赖的痛点,但目前似乎只对kts有效,了解更多细节可参见:Type-safe project dependencies
如何升级
可以直接查看Gradle文档:Upgrading your build from Gradle 6.x to the latest