Gradle 多模块依赖集中管理方案,Version Catalogs 详解(Kotlin DSL)

一、认识 Version Catalogs?

1. 什么是 Version Catalogs?

Version Catalogs 是 Gradle 官方推荐的集中式依赖版本管理方案 ,用于统一管理项目中所有依赖的版本信息------通过 TOML 格式的配置文件(默认是 libs.versions.toml),将项目中的依赖版本、库、插件及依赖分组进行结构化管理,最终实现版本集中控制、依赖引用标准化。

这种管理机制的核心优势的是「一处定义,处处引用」:既避免了依赖声明中的版本硬编码,确保项目(尤其是多模块项目)的依赖版本全局统一,又简化了依赖引用流程,降低版本冲突风险,同时提升依赖管理的可读性与可维护性。

2. Gradle 版本支持

Version Catalogs 作为 Gradle 核心的依赖管理增强功能,于 Gradle 7.0 版本作为实验性功能引入,7.4 版本提升为稳定功能详见 Gradle 7.4 发布说明),并在 Gradle 8.0+ 版本中进一步优化完善,成为官方推荐的多模块项目依赖管理方案,因此项目必须使用 Gradle 7.4 或更高版本

运行命令检查当前 Gradle 版本:

bash 复制代码
./gradlew --version

二、Version Catalogs 配置文件详解

1. 默认配置规范

Gradle 遵循「约定优于配置」原则,对 Version Catalog 配置文件有以下明确约定:

  • 文件名要求 :配置文件以 libs.versions.toml 命名
  • 文件路径 :存放于项目根目录下的 gradle 文件夹中,完整路径为:根项目/gradle/libs.versions.toml

即 Gradle 默认会读取项目根目录下的 gradle/libs.versions.toml 文件。

plaintext 复制代码
your-project/
└── gradle/
    └── libs.versions.toml  # 默认 Version Catalog 配置文件

2. 配置文件核心结构

Version Catalog 的核心配置文件(libs.versions.toml)将项目的依赖版本、库、插件和依赖组进行结构化管理。按依赖管理逻辑依次分为四个核心配置节点(Tables):

部分 作用
[versions] 定义「版本变量」,可被依赖、插件引用
[libraries] 定义「依赖声明」(groupId + artifactId + 版本),版本可引用 [versions] 中的变量
[plugins] 定义「插件声明」(插件 ID + 版本),版本可引用 [versions] 中的变量
[bundles] 定义「依赖分组」(一组相关依赖的集合,方便一次性引入)
[versions]:版本号集中定义

[versions] 块将所有依赖 / 插件的版本号抽离为可复用的 "变量",供其他节点引用,确保版本统一。

定义格式如下:

toml 复制代码
[versions]
变量名 = "版本值"

例如:

toml 复制代码
[versions]
junit = "5.9.3"
spring-boot = "3.2.0"

也支持通配符(+)或 Maven 范围语法([ )),定义动态版本的版本号:

toml 复制代码
[versions]
kotlin = "1.9.+"  # 匹配 1.9.x 最新补丁版
guava = "32.+"    # 匹配 32.x 最新次要版
jackson = "[2.0.0,)"  # 匹配 2.0.0 及以上版本
[libraries]:依赖声明

[libraries] 节点用于定义具体依赖的 GAV 坐标(group, name, version)。

依赖声明格式如下:

toml 复制代码
[libraries]
# 1. 完整写法(推荐,清晰展示 group/name)
依赖名 = { group = "组ID", name = " artifactID", version = "版本" }

# 2. 简写写法(通过 module 合并 group:name)
依赖名 = { module = "group:name", version = "版本" }

# 3. 无版本写法(版本由 BOM 管理时)
依赖名 = { module = "group:name" }

# 4. 极简写法(直接拼接 group:name:version)
依赖名 = "group:name:version"

例如:

toml 复制代码
[libraries]
spring-boot-starter-web = { 
  group = "org.springframework.boot", 
  name = "spring-boot-starter-web", 
  version = "3.2.0"
}

版本号推荐通过 version.ref = "versions 中的变量名" 引用 [versions] 中的变量:

toml 复制代码
[libraries]
spring-boot-starter-web = { 
  group = "org.springframework.boot", 
  name = "spring-boot-starter-web", 
  version.ref = "spring-boot"  # 引用 [versions] 中的 spring-boot 版本
}
[plugins]:插件管理

[plugins] 节点用于集中定义项目使用的 Gradle 插件(包含第三方和官方插件),版本可引用 [versions] 变量。

配置格式如下:

toml 复制代码
[plugins]
# 1. 第三方插件(需指定 id 和版本)
插件名 = { id = "插件ID", version = "版本" }

# 2. 官方插件(通常无需版本)
插件名 = { id = "插件ID" }

例如:

toml 复制代码
[plugins]
spring-boot = { 
  id = "org.springframework.boot", 
  version.ref = "spring-boot"  # 引用 [versions] 中的版本
}
java = { id = "java" }  # 官方插件无需版本
[bundles]:依赖分组

[bundles] 节点用于将 [libraries] 中定义的多个相关依赖组合为 "依赖包",实现一次性引入。

配置格式如下:

toml 复制代码
[bundles]
分组名 = [ "依赖名1", "依赖名2", ... ]  # 依赖名对应 [libraries] 中的键

例如,在 [bundles] 中定义一个 JUnit5 的依赖包,包含测试时需要的依赖( junit-jupiter-api, junit-jupiter-enginejunit-platform-launcher):

toml 复制代码
[bundles]
junit5 = [
    "junit-jupiter-api",    # 引用 [libraries] 中的 junit-jupiter-api
    "junit-jupiter-engine", # 引用 [libraries] 中的 junit-jupiter-engine
    "junit-platform-launcher"
]

💡 提示: [bundles] 中引用的是 [libraries] 中定义的键(Key),而不是完整的坐标。

3. 在构建脚本中引用配置

Gradle 会自动解析 libs.versions.toml 并生成类型安全的 libs 对象 ------ 这是所有配置引用的核心入口,所有在 libs.versions.toml 中定义的版本、依赖、插件、分组,都会映射为 libs 对象的属性。

别名转换规则

Gradle 生成 libs 对象时会自动将 libs.versions.toml 中的别名(依赖名、插件名、分组名)转换为符合 Kotlin 风格的属性名,核心规则如下:

  1. 分隔符转换 :别名支持 -_. 分隔符,Gradle 会自动将其规范化为点式访问器;
  2. 大小写兼容 :TOML 键名无需刻意写驼峰(如 androidx-core-ktx),转换后自动适配 Kotlin 风格(libs.androidx.core.ktx);
  3. 唯一性校验:若转换后属性名重复,Gradle 会直接报错,只需调整 TOML 中的键名即可。
TOML 中的键名(示例) libs 对象中的属性名 说明
guava libs.guava 无分隔符,直接映射
androidx-core-ktx libs.androidx.core.ktx 连字符转点
dagger_core libs.dagger.core 下划线转点

💡 提示:命名转换是 Gradle 自动完成的类型安全映射,无需手动配置,掌握该规则能快速对应 TOML 配置与构建脚本中的引用路径,避免引用报错。

引用 [libraries] 依赖

[libraries] 中定义的每个依赖都会按上述规则映射为 libs.转换后的依赖名 属性,引用时直接在 dependencies 代码块中通过 libs.转换后的依赖名 引用即可,无需手动拼接 group:name:version

示例:

toml 复制代码
# libs.versions.toml
[libraries]
guava = "com.google.guava:guava:32.1.3-jre"
spring-boot-starter-web = "org.springframework.boot:spring-boot-starter-web:3.2.0"

引用 [libraries] 中的 guavaspring-boot-starter-web 依赖:

kotlin 复制代码
// build.gradle.kts
dependencies {
    implementation(libs.guava)
    implementation(libs.spring.boot.starter.web)
}

依赖名spring-boot-starter-web通过转换规则会转换为 libs 对象的 libs.spring.boot.starter.web 属性:

引用 [plugins] 插件

[plugins] 中的插件会映射为 libs.plugins.插件名,需通过 alias() 函数引用。

示例:

toml 复制代码
# libs.versions.toml
[plugins]
java = { id = "java" }  # Java 插件

build.gradle.kts 中通过 alias() 函数引用 [plugins] 中的 java 插件:

kotlin 复制代码
// build.gradle.kts
plugins {
    alias(libs.plugins.java)
}
引用 [bundles] 依赖分组

[bundles] 中的分组会映射为 libs.bundles.分组名,可一次性引入所有依赖。

示例:

toml 复制代码
# libs.versions.toml
[bundles]
junit5 = [
    "junit-jupiter-api",    # 引用 [libraries] 中的 junit-jupiter-api
    "junit-jupiter-engine", # 引用 [libraries] 中的 junit-jupiter-engine
    "junit-platform-launcher"
]

通过 libs.bundles.junit5 一次性引入 junit5 分组中的所有依赖:

kotlin 复制代码
// build.gradle.kts
dependencies {
    testImplementation(libs.bundles.junit5)
}
引用 [versions] 版本(不推荐)

[versions] 中的版本会映射为 libs.versions.变量名,通常仅在 TOML 内部引用,而非直接在构建脚本中使用:

kotlin 复制代码
// 不推荐直接使用,建议通过 [libraries]/[plugins] 间接引用
dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter-api:${libs.versions.junit.get()}")
}

三、高级用法

1. 覆盖默认 Catalog 路径

如果不想使用默认的 gradle/libs.versions.toml,可以在 settings.gradle.kts 中配置自定义路径:

kotlin 复制代码
// settings.gradle.kts
dependencyResolutionManagement {
  versionCatalogs {
    // 默认 Catalog(名称仍为 libs)
    create("libs") {
      from(file("gradle/custom-versions.toml"))  // 自定义路径
    }
  }
}

Gradle 会优先加载 gradle/custom-libs.versions.toml,而非默认的 gradle/libs.versions.toml,且仍通过 libs 对象引用(命名空间不变)。

💡 提示 :Gradle 不支持通过 from(files()) 为同一个命名空间(如 libs)导入多个 TOML 文件 ------ 单个版本目录命名空间只能关联一个 TOML 文件。

2. 更改默认 Catalog 名称

如果默认目录名称 libs 与项目中其他扩展冲突,可修改默认目录名称:

kotlin 复制代码
// settings.gradle.kts
dependencyResolutionManagement {
    defaultLibrariesExtensionName = "projectLibs" // 新的默认目录名称
}

修改后,访问方式变为:

kotlin 复制代码
// build.gradle.kts
plugins {
    alias(projectLibs.plugins.java)
    alias(projectLibs.plugins.spring.boot)
}

dependencies {
    implementation(projectLibs.guava)
}

3. 覆盖 Catalog 的版本

导入 Catalog 后,可覆盖其中声明的版本,无需修改原目录文件:

kotlin 复制代码
// settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            from(files("gradle/custom-versions.toml")) // 导入 Catalog
            version("groovy", "3.0.6") // 覆盖 "groovy" 版本
        }
    }
}

所有引用 groovy 版本的依赖都会自动使用覆盖后的 3.0.6 版本。

💡 提示:覆盖仅影响依赖声明时使用的版本,实际解析的版本仍可能因冲突解决而变化。

4. 加载多个 Catalog 文件(多命名空间)

同时加载多个 Catalog 文件,为不同文件分配独立命名空间,实现依赖分组管理:

kotlin 复制代码
// settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        // 业务依赖目录
        create("businessLibs") {
            from(files("gradle/business.versions.toml"))
        }
        // 工具依赖目录(如构建工具、插件)
        create("toolLibs") {
            from(files("gradle/tools.versions.toml"))
        }
    }
}

不同的命名空间对应不同对象,如 businessLibstoolLibs,在构建脚本中分别访问:

kotlin 复制代码
// build.gradle.kts
dependencies {
    implementation(businessLibs.someDependency) // 业务依赖
    implementation(toolLibs.someTool) // 工具依赖
}

💡 提示 :为避免命名冲突,目录名称建议以 Libs 结尾(如 businessLibstestLibs)。

5. 多目录合并与优先级

如果导入多个目录且存在同名别名,后导入的目录会覆盖先导入的目录中的定义:

kotlin 复制代码
// settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("combinedLibs") {
            from("com.mycompany:base-catalog:1.0") // 基础目录
            from(files("gradle/custom-catalog.toml")) // 自定义目录(覆盖基础目录中的同名别名)
        }
    }
}

四、基于 version-catalog 插件发布版本目录(多项目共享)

如果需要在组织内部或外部共享版本目录(如公司内部所有项目复用一套依赖版本规范),Gradle 提供了 version-catalog 插件可将版本目录打包为独立组件发布,实现跨项目 / 团队的依赖配置共享。

1. 创建版本目录项目

为了版本目录的独立维护,建议创建一个空的 Gradle 项目 专门用于发布版本目录(也可在现有多模块项目中新增一个 catalog 子模块)。

项目目录结构:

plaintext 复制代码
catalog-project/
├── gradle/
│   └── wrapper/          # Gradle 包装器(确保统一 Gradle 版本)
├── build.gradle.kts      # 核心配置文件
├── settings.gradle.kts   # 项目设置
└── gradlew/gradle.bat    # Gradle 执行脚本

2. 定义版本目录并配置发布规则

应用插件

build.gradle.kts 中引入 version-catalog(构建版本目录)和 maven-publish(发布到仓库)插件:

kotlin 复制代码
// build.gradle.kts
plugins {
    // 用于生成可发布的版本目录组件
    `version-catalog`
    // 提供Maven仓库发布能力(必选,否则无法共享)
    `maven-publish`
}
配置项目元信息

定义项目的 Group、Version 和描述(将作为 Maven 工件的 GAV 坐标,必须唯一):

kotlin 复制代码
// build.gradle.kts
group = "com.shijie"
version = "1.0-SNAPSHOT"
description = "Shared Version Catalog for Company Projects"
定义版本目录内容

通过catalog扩展块声明版本、依赖、插件和捆绑包(对应 TOML 文件的四大核心区块):

kotlin 复制代码
// build.gradle.kts
catalog {
    versionCatalog {
        // 1. 版本变量(可被依赖/插件引用,便于统一升级)
        version("spring-boot", "3.2.0")
        version("junit", "5.9.3")
        version("kotlin", "1.9.22")

        // 2. 依赖库(group:name,版本可关联变量或直接指定)
        library("spring-boot-starter-web", "org.springframework.boot", "spring-boot-starter-web")
            .versionRef("spring-boot")  // 关联上面定义的spring-boot版本
        library("junit-jupiter", "org.junit.jupiter", "junit-jupiter-api")
            .versionRef("junit")
        library("lombok", "org.projectlombok", "lombok")
            .version("1.18.30")  // 直接指定版本(适用于较少变更的依赖)

        // 3. 插件(id:group:version)
        plugin("spring-boot", "org.springframework.boot", "3.2.0")

        // 4. 依赖捆绑包(将多个相关依赖组合,简化引用)
        bundle("spring-web", listOf("spring-boot-starter-web"))  // 包含web starters
        bundle("junit5", listOf("junit-jupiter"))  // 包含JUnit5核心依赖
    }
}
配置发布仓库

通过publishing块指定发布目标(本地仓库用于测试,私服用于团队共享):

kotlin 复制代码
// build.gradle.kts
publishing {
    publications {
        // 创建Maven格式的发布物,关联版本目录组件
        create<MavenPublication>("maven") {
            from(components["versionCatalog"])  // 核心:将版本目录打包为发布组件
        }
    }
    repositories {
        // 本地仓库(开发测试用,路径:~/.m2/repository)
        mavenLocal()
        
        // 企业私有仓库(如Nexus、Artifactory,团队共享用)
        maven {
            url = uri("https://your-company-nexus.com/repository/maven-releases/")
            // 仓库认证(根据私服配置填写)
            credentials {
                username = "your-username"
                password = "your-password"
            }
        }
    }
}

3. 发布版本目录到仓库

在版本目录项目根目录执行 Gradle 发布命令:

bash 复制代码
# 发布到本地Maven仓库(用于本地测试)
./gradlew publishToMavenLocal

# 发布到配置的私服(团队共享)
./gradlew publish

发布成功后,仓库中会生成以下工件(GAV:com.shijie:version-catalog:1.0-SNAPSHOT):

4. 其他项目引用发布的版本目录

settings.gradle.kts 中通过 dependencyResolutionManagement 引用版本目录:

kotlin 复制代码
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            // 引用发布的团队版本目录
            from("com.shijie:catalog-project:1.0-SNAPSHOT")
        }
    }

    repositories {
        mavenCentral()
        mavenLocal() // 本地仓库(测试用)
        maven { url = uri("https://your-nexus-url/repository/maven-releases/") }
    }
}

build.gradle.kts 中通过 libs 前缀引用共享的依赖和插件:

kotlin 复制代码
plugins {
    // 引用版本目录中的 spring-boot 插件
    alias(libs.plugins.spring.boot)
}

dependencies {
     // 引用版本目录中的依赖
    implementation(libs.spring.boot.starter.web)
}
相关推荐
电商API_1800790524710 小时前
大麦网API实战指南:关键字搜索与详情数据获取全解析
java·大数据·前端·人工智能·spring·网络爬虫
dasi022710 小时前
Java 趣闻
java
C雨后彩虹10 小时前
synchronized高频考点模拟面试过程
java·面试·多线程·并发·lock
JAVA+C语言10 小时前
Java ThreadLocal 的原理
java·开发语言·python
lkbhua莱克瓦2410 小时前
进阶-SQL优化
java·数据库·sql·mysql·oracle
行稳方能走远10 小时前
Android java 学习笔记 1
android·java
kaico201810 小时前
多线程与微服务下的事务
java·微服务·架构
zhglhy10 小时前
QLExpress Java动态脚本引擎使用指南
java
zhimingwen10 小时前
【開發筆記】修復 macOS 上 JADX 啟動崩潰並實現快速啟動
android·macos·反編譯