此功能默认未启用。 |
支持的插件
配置缓存对插件实现提出了新的要求。因此,核心 Gradle 插件和社区插件都需要进行调整,以确保兼容性。
本节提供有关当前支持的详细信息
核心 Gradle 插件
大多数核心 Gradle 插件目前都支持配置缓存
JVM 语言和框架 |
原生语言 |
打包与分发 |
---|---|---|
代码分析 |
IDE 项目文件生成 |
实用工具 |
✓ |
支持的插件 |
⚠ |
部分支持的插件(任务总是禁用配置缓存) |
⚠* |
部分支持的插件(某些功能可能会禁用配置缓存) |
尚未实现
目前尚未提供某些 Gradle 功能的配置缓存支持。这些功能将在未来的 Gradle 版本中支持。
使用 TestKit 运行构建时使用 Java Agent
当使用TestKit运行构建时,配置缓存可能会干扰应用于这些构建的 Java Agent,例如 Jacoco agent。
请参阅 gradle/gradle#25979。
细粒度跟踪 Gradle 属性作为构建配置输入
目前,所有 Gradle 属性的外部源——例如 gradle.properties
文件(在项目目录和 GRADLE_USER_HOME
中)、环境变量、设置属性的系统属性以及通过命令行标志指定的属性——都被视为构建配置输入,无论它们是否实际在配置期间使用。
但是,这些源不包含在配置缓存报告中。
请参阅 gradle/gradle#20969。
Java 对象序列化
Gradle 允许支持 Java 对象序列化 协议的对象存储在配置缓存中。
目前的实现仅限于实现了 java.io.Externalizable
接口或实现了 java.io.Serializable
接口并定义了以下方法组合之一的可序列化类:
-
一个
writeObject
方法与一个readObject
方法结合,以精确控制要存储的信息; -
一个
writeObject
方法,没有相应的readObject
;writeObject
最终必须调用ObjectOutputStream.defaultWriteObject
; -
一个
readObject
方法,没有相应的writeObject
;readObject
最终必须调用ObjectInputStream.defaultReadObject
; -
一个
writeReplace
方法,允许类指定一个替代对象来写入; -
一个
readResolve
方法,允许类指定一个替代对象来读取;
以下 Java 对象序列化功能不受支持:
-
serialPersistentFields
成员用于显式声明哪些字段是可序列化的;如果存在,该成员将被忽略;配置缓存认为除transient
字段外的所有字段都是可序列化的; -
ObjectOutputStream
的以下方法不受支持,并将抛出UnsupportedOperationException
:-
reset()
、writeFields()
、putFields()
、writeChars(String)
、writeBytes(String)
和writeUnshared(Any?)
。
-
-
ObjectInputStream
的以下方法不受支持,并将抛出UnsupportedOperationException
:-
readLine()
、readFully(ByteArray)
、readFully(ByteArray, Int, Int)
、readUnshared()
、readFields()
、transferTo(OutputStream)
和readAllBytes()
。
-
-
通过
ObjectInputStream.registerValidation
注册的验证将被简单地忽略; -
readObjectNoData
方法(如果存在)永不被调用;
请参阅 gradle/gradle#13588。
在执行时访问构建脚本的顶层方法和变量
在构建脚本中重用逻辑和数据的常见方法是将重复部分提取到顶层方法和变量中。但是,如果启用了配置缓存,目前不支持在执行时调用此类方法。
对于用 Groovy 编写的构建脚本,任务会失败,因为找不到该方法。以下代码片段在 listFiles
任务中使用了顶层方法:
def dir = file('data')
def listFiles(File dir) {
dir.listFiles({ file -> file.isFile() } as FileFilter).name.sort()
}
tasks.register('listFiles') {
doLast {
println listFiles(dir)
}
}
启用配置缓存运行任务会产生以下错误:
Execution failed for task ':listFiles'. > Could not find method listFiles() for arguments [/home/user/gradle/samples/data] on task ':listFiles' of type org.gradle.api.DefaultTask.
为了防止任务失败,请将被引用的顶层方法转换为类中的静态方法:
def dir = file('data')
class Files {
static def listFiles(File dir) {
dir.listFiles({ file -> file.isFile() } as FileFilter).name.sort()
}
}
tasks.register('listFilesFixed') {
doLast {
println Files.listFiles(dir)
}
}
用 Kotlin 编写的构建脚本根本不能在执行时将引用顶层方法或变量的任务存储在配置缓存中。存在此限制是因为捕获的脚本对象引用无法序列化。第一次运行 Kotlin 版本的 listFiles
任务时,会因配置缓存问题而失败。
val dir = file("data")
fun listFiles(dir: File): List<String> =
dir.listFiles { file: File -> file.isFile }.map { it.name }.sorted()
tasks.register("listFiles") {
doLast {
println(listFiles(dir))
}
}
为了使此任务的 Kotlin 版本与配置缓存兼容,请进行以下更改:
object Files { (1)
fun listFiles(dir: File): List<String> =
dir.listFiles { file: File -> file.isFile }.map { it.name }.sorted()
}
tasks.register("listFilesFixed") {
val dir = file("data") (2)
doLast {
println(Files.listFiles(dir))
}
}
1 | 在对象中定义方法。 |
2 | 在较小的作用域中定义变量。 |
请参阅 gradle/gradle#22879。
使用构建服务使配置缓存失效
目前,如果 ValueSource
的值在配置时被访问,则无法将 BuildService
的提供者或从其派生的提供者(通过 map
或 flatMap
)作为 ValueSource
的参数使用。当此类 ValueSource
在作为配置阶段一部分执行的任务中获取时,例如 buildSrc
构建的任务或包含的贡献插件的构建,也适用同样的情况。
请注意,使用 @ServiceReference
或将 BuildService
存储在任务的 @Internal
注释属性中是安全的。
一般来说,此限制使得无法使用 BuildService
使配置缓存失效。
请参阅 gradle/gradle#24085。
使用任意提供者作为构建事件监听器
构建事件监听器注册方法 BuildEventsListenerRegistry.onTaskCompletion
接受任何 OperationCompletionListener
实现的任意提供者。然而,当使用配置缓存时,目前仅支持从 BuildServiceRegistry.registerIfAbsent
或 BuildServiceRegistration.getService
返回的提供者。从 Gradle 9 开始,使用其他类型的提供者(包括 registerIfAbsent(…).map { it }
)会导致发出配置缓存问题。在此之前,此类提供者会被静默忽略。
查阅采用指南,了解如何暂时抑制这些问题(如果被丢弃的监听器不影响您的构建)。
请参阅 gradle/gradle#33772。