30、Gradle高级主题:复合构建、Gradle Modules、自定义构建逻辑与未来展望
各位同学,欢迎来到第三十讲。走到这里,Gradle 的核心知识你已经掌握得差不多了。今天我们来聊聊那些真正让 Gradle 变得“高级”的东西——复合构建、模块化、自定义逻辑,以及 Gradle 9.x 的新方向。
说实话,这些内容在日常小项目中可能用不上。但一旦你开始维护大型项目、多模块仓库,或者需要构建一套公司级的构建规范,这些就是你的“杀手锏”。
复合构建(Composite Build)
先问一个问题:你手头有两个独立的 Gradle 项目,一个是你正在开发的业务库,另一个是你们团队维护的公共工具库。你想在业务库里直接调试工具库的最新代码,怎么办?
传统做法是把工具库发布到本地 Maven 仓库,然后业务库引用。每次改完工具库,都要 publishToMavenLocal,再刷新业务库。太慢了。
复合构建就是来解决这个问题的。
它允许你把多个独立的 Gradle 项目“组合”在一起,让它们像一个项目一样互相依赖。你可以在业务库的 settings.gradle 里这样写:
// settings.gradle
rootProject.name = 'my-business-app'
includeBuild('../my-tool-library')
然后,在业务库的 build.gradle 里,直接引用工具库的模块:
dependencies {
implementation('com.mycompany:my-tool-core:1.0.0') // 这个版本号会被复合构建覆盖
}
嗯,这里要注意:复合构建会“覆盖”你声明的版本号。Gradle 会优先使用被包含项目的实际代码,而不是从仓库里下载的 jar 包。
复合构建的典型场景
- 本地开发调试:同时修改多个关联项目
- 插件开发:在宿主项目中直接调试自定义插件
- 构建逻辑复用:把公共构建逻辑抽取为独立项目,通过复合构建引入
Gradle Modules 与模块化设计
说到模块化,很多人第一反应是 Java 9 的 module-info.java。但 Gradle 的模块化,更多是指构建层面的模块拆分。
我个人习惯把项目拆成三层:
- API 模块:只暴露接口和模型,不包含实现
- Core 模块:核心业务逻辑,依赖 API 模块
- App 模块:最终的可执行应用,依赖 Core 模块
这样做的好处是:依赖关系清晰,编译速度更快。因为 Gradle 可以并行构建互不依赖的模块。
举个例子,一个典型的 settings.gradle 是这样的:
rootProject.name = 'my-application'
include 'my-api'
include 'my-core'
include 'my-app'
// 还可以包含独立的构建逻辑模块
includeBuild('gradle/plugins')
每个模块的 build.gradle 只声明自己需要的依赖:
// my-core/build.gradle
dependencies {
implementation project(':my-api')
implementation 'com.google.guava:guava:32.1.3-jre'
}
build.gradle 里,用 allprojects 统一声明。结果每次改一个模块的依赖,整个项目都要重新配置。后来我改成每个模块独立声明,配合 dependencyManagement 统一版本号,构建速度提升了 40%。
自定义构建逻辑
Gradle 最强大的地方,就是你可以用 Groovy 或 Kotlin 写自己的构建逻辑。说白了,Gradle 本身就是一个编程框架。
常见的自定义方式有三种:
| 方式 | 适用场景 | 复杂度 |
|---|---|---|
| buildSrc | 单个项目内的自定义逻辑 | 低 |
| 复合构建 + 插件项目 | 跨项目复用构建逻辑 | 中 |
| 独立插件发布 | 公司级/开源级构建规范 | 高 |
我个人最推荐的是复合构建 + 插件项目的方式。你想想看,把构建逻辑放在 buildSrc 里,虽然方便,但没法跨项目复用。而发布独立插件又太重了,每次改个配置都要发版。
复合构建正好折中:
// 在 gradle/plugins 目录下创建一个独立的插件项目
// gradle/plugins/build.gradle.kts
plugins {
`java-gradle-plugin`
}
gradlePlugin {
plugins {
register("my-conventions") {
id = "com.mycompany.conventions"
implementationClass = "com.mycompany.gradle.MyConventionsPlugin"
}
}
}
// 然后在主项目的 settings.gradle 里引入
includeBuild('gradle/plugins')
这样,你可以在插件项目里写任何复杂的构建逻辑,主项目直接 apply 即可。改完插件代码,不需要发布,直接运行主项目的任务就能生效。
Task 和 Plugin。Task 定义“做什么”,Plugin 定义“什么时候做”以及“需要哪些配置”。记住这个原则,你的构建逻辑就会清晰很多。
未来展望:Gradle 9.x 新特性
聊完了现在,我们看看未来。Gradle 9.x 有几个方向值得关注:
1. 更快的配置阶段
Gradle 8.x 已经引入了 配置缓存,9.x 会进一步优化。说白了,就是让 settings.gradle 和 build.gradle 的解析速度更快。对于大型项目,配置阶段可能从几十秒缩短到几秒。
2. 更完善的 Kotlin DSL 支持
虽然现在 Kotlin DSL 已经很好用了,但 9.x 会进一步减少 Groovy 和 Kotlin 之间的行为差异。我个人建议,新项目直接用 Kotlin DSL,Groovy 的灵活性虽然高,但 IDE 支持和类型安全方面,Kotlin 明显更胜一筹。
3. 增量构建的进一步优化
Gradle 的增量构建已经很智能了,但 9.x 会引入更细粒度的输入跟踪。比如,以前你改了一个资源文件,整个 processResources 任务都要重跑。未来可能只重跑受影响的那部分。
4. 构建扫描的深度集成
构建扫描(Build Scan)现在是 Gradle 的标配。9.x 会把它更深度地集成到构建流程中,甚至可以在构建失败时自动生成诊断报告。
--configuration-cache 参数,你现在就可以用起来。
知识体系总览
为了帮你理清这一章的知识结构,我画了一张图:
这张图把四个核心主题串在了一起。你会发现,它们其实都指向同一个目标:让构建过程更快、更灵活、更可维护。
好了,这一讲的内容就到这里。复合构建和模块化设计,是我在实际项目中用得最多的技巧。如果你现在正在维护一个中型以上的项目,我强烈建议你试试复合构建——哪怕只是把插件代码抽出来单独管理,都会让你的构建逻辑清晰很多。
至于 Gradle 9.x,保持关注就好。Gradle 的迭代速度很快,但核心思想不会变:约定优于配置,灵活但不失严谨。
公众号:蓝海资料掘金营,微信 deep3321