名词解释教学工作区 · 课程 0015 · 形态 单概念 · 约 6 分钟 · 前置:0004 · Node.js / npm / pnpm(先分清"装包"的角色) · 相关:0016 · 静态部署与其它部署 · 2026-10-01

Gradle:从源码到产物,这条流水线谁在管

你能做到:看着一个项目的构建配置,说清它到底在做什么 —— 先取依赖、再编译、然后测试与打包,以及为什么第二次构建会快很多; 自己敲一句 ./gradlew build,知道它在背后跑了哪些步骤。

1 | 定义

Gradle(构建工具 build tool):把「从源码到产物」要做的事拆成一个个 任务 task,再按任务之间的依赖排成一张 依赖图 dependency graph 依次执行, 顺手替你解析、下载要用到的外部库。它跟包管理器的分工是: 一个管「装什么」,一个管「做出什么」。 像厨房里那张流程单:从原料到出餐要洗、切、炒,谁先谁后、切过的就不必再切; 它管的就是这条线 —— 你只说一句「出餐」,它照着单子把每道工序派下去。

2 | 它解决什么麻烦

没有构建工具的时候,一个项目从源码走到能交付,中间全是没人愿意手管的琐事:

这四件事有个共同点:它们属于流程,不属于程序本身。构建工具专门接管这一段。

3 | 它怎么解决

构建脚本 你写下的规则 -> 任务 task 一件可执行的事 -> 依赖图 dependency graph 谁必须排在谁之前 -> 增量构建 incremental build 输入没变就沿用上次 -> 产物 build 可交付的那份东西

4 | 用它的代价

5 | 真实使用场景

场景一:本地跑构建与测试。

./gradlew build        # 按依赖跑完编译、测试、打包,产物进 build/
./gradlew test         # 只跑到测试;已经算过的步骤自动跳过
./gradlew bootRun      # Spring Boot 项目:直接起服务,不必先手动打包

命令前那个 ./gradlew 就是项目自带的 Wrapper,所以第一次跑它会先把对应版本的 Gradle 拉下来。

场景二:CI/CD 流水线里构建。

./gradlew --no-daemon build   # 一次性环境:跑完就退出,不留常驻进程
./gradlew --offline build     # 依赖已在缓存里时,不联网也能构建

流水线用的是用完即弃的容器,常驻进程留不下来,反而成了纯开销,所以显式关掉;要让结果可复现, 还得把 Gradle 版本与依赖来源一起锁死。

场景三:多模块与 Android 项目。

一个仓库拆成 app/、core/ 等多个模块时,settings.gradle 列出成员, ./gradlew :app:build 这种带路径的任务名可以只构建其中一块。Android 项目也是同一套配置, 只是插件换成了 Android Gradle Plugin —— 这也是 Gradle 最常见的一张门面。

6 | 和相近的东西怎么分

先问一句:你要解决的是「怎么编」,还是「编的流程谁来管」? 再问一句:这句话说的是一步,还是整条路?

名称它是什么和 Gradle 什么关系
Maven 更早的 Java 构建工具:流程写在一份 XML 里,目录结构与生命周期由它规定 同类替代品:约定更强、写起来更啰嗦;要自定义流程时 Gradle 更灵活,代价是你要会写脚本
Ant 纯脚本式构建工具:目标与步骤全靠你一条条写,没有默认流程 上一代:它只执行你写的步骤,不替你做依赖解析与增量判断
Make 最朴素的构建工具:写明「目标依赖哪些文件」,再按文件时间戳重建 思路相通(依赖图 + 增量),但它没有依赖解析与远程仓库,跨平台也得自己想办法
npm scripts / pnpm 包管理器的附带能力:在配置里写几条命名命令,拼起来当流程用 一半重叠:它擅长「装什么」,流程靠一串命令硬拼,任务依赖、增量、缓存都要你自己补
Bazel 为超大仓库设计的构建系统:跨语言,强调可复现与远程缓存 同一位置、不同量级:仓库大到需要分布式缓存时,才值得付它那份学习成本
编译器 把源码翻译成机器能执行的指令的那个程序 上下两层:编译只是构建里的一步;取依赖、跑测试、打包、记住哪步能跳过,都不归它管

一句话分工:包管理器管「装」,编译器管「翻」,构建工具管「编排整条路」,部署工具管「送出去」。

7 | 常见误解

8 | 练习

三题自测,每题只有一个正确选项;选完立刻看到解释。

1. 只改了一个源文件后重新构建,没变的任务不再重做 —— 这个机制叫什么?

对。Gradle 给每个任务记下输入与输出,输入没变就直接沿用上次结果;这会跳过没必要的重做,但不会替你跳过你没让它跳的测试。

2. 项目里带一个 gradlew,替你保证了什么?

对。Wrapper 钉住的是构建工具本身的版本;依赖版本要靠依赖声明与锁定,产物是否可复现还牵涉编译参数与环境,三件事别混成一件。

3. 把各个任务的前后顺序算清楚、决定谁先跑的那张图,叫什么?

对。你只声明任务与依赖,图由 Gradle 算出来;顺序不是它硬编的,而是从你的声明里推出来的。