隔离项目是一项预 Alpha 版本的 Gradle 功能,它扩展了配置缓存,以进一步提高性能,特别是 Android Studio 和 IDEA 同步的性能。
启用隔离项目后,Gradle 项目的配置模型彼此“隔离”。这意味着应用于项目的构建逻辑(例如构建脚本或插件)无法直接访问另一个项目的可变状态。这允许每个项目的配置和工具模型创建安全地并行运行,每个项目的结果可以独立缓存和失效。
截至 Gradle 8.11 的状态
启用隔离项目后,Gradle 在 IDE 同步期间应用两级缓存
-
Gradle 首先应用粗粒度缓存。
为此,Gradle 缓存整个同步操作的结果,并在影响 IDE 模型的任何内容未发生更改时重用它。当可以重用缓存条目时,Gradle 会短路整个同步操作,并将缓存的结果返回到 IDE。
-
通常,设置和构建脚本会影响 IDE 模型,但项目的源代码不会。因此,当这些脚本发生更改时,无法重用缓存条目。当这种情况发生时,Gradle 会回退到细粒度缓存。
为此,Gradle 缓存为每个项目创建工具模型的结果,并在影响它们的任何内容未发生更改时重用这些模型。当可以重用项目的缓存模型时,Gradle 会短路该项目的所有工作,包括配置阶段和其他工作(例如依赖解析)。
这意味着 Gradle 将仅配置和创建配置已更改的项目的工具模型。这项工作针对每个项目并行完成。
当前限制
隔离项目是一项预 Alpha 功能,因此,当前的实现存在许多限制。这些限制将在未来的 Gradle 版本中解决
-
Gradle、IntelliJ IDEA、Android Studio 和 Kotlin 插件尚未 100% 与隔离项目兼容,因此您应该预期会看到一些违规报告。各个团队正在积极解决这些不兼容问题。
-
并行配置不支持 按需配置。所有项目都将被配置,即使它们没有运行任务。
-
对包含构建的更改会使所有缓存结果失效,即使更改不会影响缓存结果。
-
该实现不利用隔离来限制峰值内存消耗。目前,峰值内存消耗是必须配置的项目数量的函数。
-
所有缓存,包括配置缓存,都在本地计算机上完成。尚不支持远程缓存。
我该如何使用它?
您需要 Gradle 8.5 或更高版本才能使用隔离项目,最好是最近的 nightly 版本。您还应该使用最新版本的 IDEA 或 Android Studio。
该功能默认处于关闭状态。您可以通过将 org.gradle.unsafe.isolated-projects
系统属性设置为 true
来启用它。例如
$ gradle build -Dorg.gradle.unsafe.isolated-projects=true
启用后,当构建逻辑尝试跨项目边界并访问另一个项目的模型时,Gradle 将使构建失败。Gradle 会在配置缓存报告中收集所有这些访问问题,就像处理其他问题一样。
配置缓存命令行选项可用于控制 Gradle 如何处理这些问题。例如
-
--configuration-cache-problems=warn
可用于将访问问题视为警告而不是错误。 -
-Dorg.gradle.configuration-cache.max-problems=x
可用于增加报告中包含的最大问题数量。
您还可以使用 -Dorg.gradle.internal.invalidate-coupled-projects=false
在存在访问问题时强制执行并行配置。
请注意,这些选项禁用了在启用隔离项目时使执行并行和缓存安全性的验证,因此当使用它们时,您可能会看到一些意外的行为。
构建逻辑约束
隔离项目阻止构建逻辑访问另一个项目的状态。这包括
-
使用
Project
类型上的大多数方法。允许使用少量返回关于项目的不可变信息的方法-
getName()
-
getPath()
-
getBuildTreePath()
-
getProjectDir()
-
getRootDir()
-
getChildProjects()
-
getSubprojects()
-
getAllProjects()
-
project()
重载 -
subprojects()
重载 -
allprojects()
重载
-
请注意,隔离项目是一项预 Alpha 功能。这些约束不是最终的,可能会随时更改。
变更日志
Gradle 8.11
并行配置项目
当从命令行构建(即用于任务执行)并启用隔离项目时,项目现在并行配置。
并行配置尚不支持按需配置。所有项目都将被配置,即使那些没有要运行的任务的项目也是如此。如果这种权衡是不希望看到的,并且您希望项目使用按需配置进行串行配置,请将 org.gradle.internal.isolated-projects.configure-on-demand.tasks
系统属性设置为 true
。
Gradle 8.9
IsolatedProject
在组合构建中提供项目标识符
IsolatedProject 类型在 Gradle 8.8 中引入,用于显式标记跨项目安全访问的项目状态。
Gradle 8.9 添加了一个 buildTreePath
成员,它在 组合构建 设置中充当唯一的项目标识符。
Gradle 8.8
新的 Gradle 生命周期回调
此版本引入了一个新的 GradleLifecycle
API,可以通过 gradle.lifecycle
访问,插件作者和构建工程师可以使用它来注册在构建生命周期中特定点执行的操作。
注册为 GradleLifecycle
回调(当前为 beforeProject
和 afterProject
)的操作是隔离的,在每个项目私有的隔离上下文中运行。这将允许 Gradle 执行额外的性能优化,并且在未来需要利用构建配置阶段的并行性。
虽然现有的回调继续工作,但我们鼓励大家采用新的 API 并向我们提供早期反馈。
下面的示例展示了如何在 settings 脚本或 settings 插件 中使用这个新的 API 来将配置应用于所有项目,同时避免 跨项目配置
include("sub1")
include("sub2")
gradle.lifecycle.beforeProject {
apply(plugin = "base")
repositories {
mavenCentral()
}
}
隔离项目视图
现在支持通过 Project.getIsolated()
获取项目的隔离视图作为 IsolatedProject
。
该视图仅公开在并行运行构建配置阶段(将在未来版本中支持)时,跨项目边界安全访问的那些属性。
下面的示例展示了如何从 Project
配置回调中使用 API 以并行安全的方式查询根项目目录
gradle.lifecycle.beforeProject {
val rootDir = project.isolated.rootProject.projectDirectory
println("The root project directory is $rootDir")
}