Gradle 构建缓存整体认知

1.1 构建缓存的核心原理

Gradle 构建缓存是一项将任务(Task)的输入与输出进行哈希签名后存储复用结果的机制。每次构建时,Gradle 根据当前任务的输入(源文件、依赖版本、配置参数等)计算出一个唯一缓存键(cache key),并在本地或远程缓存中查找该键是否存在。若命中,则直接复用输出,跳过任务执行;若未命中,则正常执行任务并将输出存入缓存,供后续构建使用。

其核心依赖三要素:

  • 输入快照(Input Snapshot):对任务的所有输入(文件内容、类路径、属性等)进行哈希。
  • 缓存键(Cache Key):由输入快照、任务类名、执行参数等组合生成。
  • 输出归档(Output Archive):任务产物(class 文件、JAR、报告等)打包后与缓存键关联存储。
特性传统构建开启缓存构建
编译时间(无变更)全量编译(~60秒)缓存命中(~2秒)
输入哈希计算无每次必须计算(开销极小)
任务执行次数每次构建全部执行仅输入变更时执行
远程协作不支持可共享缓存(远程缓存)
通过日志确认缓存行为: 在 gradle.properties 中添加 org.gradle.caching.debug=true,构建时即可看到每个任务的缓存键、命中状态及存储耗时。

1.2 构建生命周期与缓存的交互

Gradle 构建生命周期分为三个阶段:初始化(Initialization)、配置(Configuration)、执行(Execution)。缓存机制出现在执行阶段。具体流程如下:

  1. Gradle 为每个任务确定执行所需的输入。
  2. 在执行前,通过缓存键查询本地/远程缓存。
  3. 若命中 → 跳过任务执行,直接将输出解压到输出目录。
  4. 若未命中 → 正常执行任务,执行完成后将输出打包并写入缓存。
  5. 最终汇总构建结果。

下图清晰展示了该流程:

构建缓存交互流程图 计算任务输入哈希 组装缓存键 (Cache Key) 查询本地/远程缓存 命中? 未命中 → 执行任务 打包输出并写入缓存 命中 → 复用输出 构建完成:命中记录 + 跳过耗时 说明:虚线箭头表示命中分支,实线箭头表示未命中分支。

1.3 缓存带来的加速效果

缓存对多模块项目、频繁拉取分支的场景提升尤为显著。以下是典型实践中的加速数据:

  • 全量构建(无缓存):5分20秒
  • 二次构建(仅有增量文件变更):45秒(增量构建)
  • 跨分支切换后首次构建(缓存命中部分任务):1分10秒
  • 跨机器共享缓存(远程缓存):完全一致环境最快可达 5 秒完成

开启构建缓存的配置极为简单:在 gradle.properties 或 build.gradle 中启用即可:

# gradle.properties
org.gradle.caching=true
# 可选:指定本地缓存大小
org.gradle.caching.local.cacheSizeMB=2048
注意: 缓存并不适用于所有任务。例如会改变全局状态的任务(如自定义代码生成器依赖当前时间戳)不应被缓存。此类任务需手动标记为 outputs.cacheIf { false } 或使用 @DisableCachingByDefault 注解。

为验证加速效果,可以在构建后通过 --build-cache 参数显式启用,并观察控制台日志中的缓存命中状态:

# 启用缓存执行构建
gradle build --build-cache

# 输出示例(关键行)
> Task :core:compileJava FROM-CACHE
> Task :data:compileJava UP-TO-DATE
> Task :web:compileJava FROM-CACHE
BUILD SUCCESSFUL in 12s
3 actionable tasks: 2 from cache, 1 up-to-date

其中 FROM-CACHE 表示任务输出来自缓存,未实际执行;UP-TO-DATE 表示本地增量构建认为无需执行。缓存与增量构建协同工作,进一步压缩构建耗时。