22、版本目录(Version Catalog):libs.versions.toml、集中管理依赖版本、多项目共享
说实话,Gradle 项目里最让人头疼的事情之一,就是依赖版本的管理。
我记得刚接手一个老项目时,打开 build.gradle 文件,好家伙,密密麻麻的依赖声明。同一个 Guava 版本,在三个子模块里写了三遍。升级版本?那得全局搜索替换,改漏一个就等着编译报错吧。
后来 Gradle 7.0 正式推出了 Version Catalog,也就是版本目录。这玩意儿说白了,就是给你一个集中存放依赖版本的地方。所有模块都从这个目录里读取,版本统一,升级方便。我个人习惯,现在新建项目第一件事就是配好 libs.versions.toml。
什么是 Version Catalog?
Version Catalog 是 Gradle 提供的一种依赖版本管理机制。它把依赖的 group、name、version 抽离到一个单独的 TOML 文件中。这个文件通常叫 libs.versions.toml,放在项目的 gradle 目录下。
你想想看,以前我们写依赖是这样的:
implementation 'com.google.guava:guava:31.1-jre'
用了 Version Catalog 之后,变成这样:
implementation libs.guava
清爽多了吧?版本号只在一个地方维护,所有模块共享。
libs.versions.toml 文件结构
这个 TOML 文件分为三个主要区域:[versions]、[libraries] 和 [plugins]。我画了一张图,帮你快速理解它的结构:
如何定义版本和依赖
我们来看一个完整的 libs.versions.toml 示例:
[versions]
guava = "31.1-jre"
spring-boot = "2.7.0"
junit-jupiter = "5.8.2"
retrofit = "2.9.0"
okhttp = "4.9.3"
[libraries]
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
spring-boot-starter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web", version.ref = "spring-boot" }
spring-boot-starter-test = { group = "org.springframework.boot", name = "spring-boot-starter-test", version.ref = "spring-boot" }
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
这里有个细节要注意:version.ref 引用了 [versions] 中定义的版本号。这样改版本时,只需要改 [versions] 里的值,所有引用它的依赖都会同步更新。
guava 而不是 guavaVersion,用 spring-boot 而不是 springBootVersion。这样在 libs.guava 调用时,命名更自然。
在 build.gradle 中使用 Version Catalog
配置好 TOML 文件后,在 build.gradle 中就可以直接引用了:
dependencies {
implementation libs.guava
implementation libs.spring.boot.starter.web
testImplementation libs.junit.jupiter
implementation libs.retrofit
implementation libs.okhttp
}
是不是很直观?libs 是 Gradle 自动生成的访问器。它会根据 TOML 文件中的 [libraries] 块,自动生成对应的属性方法。
对于插件,在 plugins 块中这样使用:
plugins {
alias libs.plugins.spring.boot
}
注意这里用的是 alias 关键字,而不是 id。这是 Gradle 专门为 Version Catalog 提供的语法。
多项目共享依赖版本
在多模块项目中,Version Catalog 的优势更加明显。你只需要在根项目的 gradle/libs.versions.toml 中定义一次,所有子模块都能共享。
举个例子,假设你有三个子模块:core、web、api。每个模块都需要 Guava 和 Spring Boot。以前你需要在三个 build.gradle 里分别写版本号。现在只需要在根目录的 TOML 文件中定义一次,每个子模块直接引用 libs.guava 即可。
// core/build.gradle
dependencies {
implementation libs.guava
}
// web/build.gradle
dependencies {
implementation libs.guava
implementation libs.spring.boot.starter.web
}
// api/build.gradle
dependencies {
implementation libs.guava
implementation libs.retrofit
}
升级版本时,只需要修改 TOML 文件中的版本号,所有模块自动生效。我曾经在一个 20 多个模块的项目里,用这个方式把 Spring Boot 从 2.6 升级到 2.7,只改了一行代码,编译全部通过。要是以前,我得逐个模块检查,至少得花半天时间。
版本目录的命名规范
Gradle 会自动将 TOML 文件中的 key 转换为驼峰命名。比如:
| TOML 中的 key | 生成的访问器 |
|---|---|
spring-boot-starter-web |
libs.spring.boot.starter.web |
junit-jupiter |
libs.junit.jupiter |
my-library |
libs.my.library |
命名时尽量保持简洁,避免过长的 key。我个人习惯用 - 分隔单词,这样生成的访问器可读性更好。
避坑指南
- TOML 文件位置必须正确:必须放在
gradle/libs.versions.toml,不能放在项目根目录或其他位置。否则 Gradle 找不到。 - 版本号不要硬编码在 [libraries] 中:虽然可以直接写
version = "31.1-jre",但这样就失去了集中管理的意义。建议统一使用version.ref引用。 - 插件版本也要集中管理:很多同学只管理依赖版本,忽略了插件版本。其实插件版本也应该放在
[versions]中统一管理。 - 不要混用旧语法:一旦使用了 Version Catalog,就不要再在
build.gradle中直接写版本号了。混用会导致维护混乱。
进阶用法:多目录与条件依赖
对于大型项目,一个 TOML 文件可能不够用。Gradle 支持通过 settings.gradle 配置多个版本目录:
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files("gradle/libs.versions.toml"))
}
testLibs {
from(files("gradle/test-libs.versions.toml"))
}
}
}
这样你就可以在子模块中分别使用 libs 和 testLibs 两个目录。不过我个人建议,除非项目特别大,否则一个 TOML 文件就够了。文件多了反而不好管理。
- Version Catalog 通过
libs.versions.toml集中管理依赖版本 - 文件分为
[versions]、[libraries]、[plugins]三个区域 - 使用
libs.xxx在build.gradle中引用依赖 - 多模块项目共享同一个版本目录,升级版本只需改一处
- 插件版本也要纳入版本目录管理
好了,关于 Version Catalog 的核心内容就这些。说白了,它就是 Gradle 官方给你提供的一个依赖版本管理工具,用起来简单,效果却很好。如果你还在手动管理版本号,我强烈建议你试试这个方式。相信我,一旦用上,你就回不去了。
公众号:蓝海资料掘金营,微信deep3321