Gradle依赖管理
# Gradle 依赖管理
依赖管理是构建工具的核心能力。Gradle 的依赖管理比 Maven 更细粒度、更灵活,本文从配置项、Version Catalog、排除依赖、BOM 等方面全面讲解。
# 依赖配置项(Configuration)
# 与 Maven Scope 的对比
Maven 只有 6 种 scope(compile / provided / runtime / test / system / import),而 Gradle 提供了更细粒度的配置项:
| Gradle 配置项 | 说明 | 编译 | 运行 | 测试 | 打包 | Maven 对应 |
|---|---|---|---|---|---|---|
implementation | 主依赖,不暴露给下游 | ✅ | ✅ | ✅ | ✅ | compile |
api | 主依赖,暴露给下游 | ✅ | ✅ | ✅ | ✅ | compile(传递) |
compileOnly | 仅编译时需要 | ✅ | ❌ | ✅ | ❌ | provided |
runtimeOnly | 仅运行时需要 | ❌ | ✅ | ✅ | ✅ | runtime |
testImplementation | 测试编译和运行 | ❌ | ❌ | ✅ | ❌ | test |
testCompileOnly | 仅测试编译 | ❌ | ❌ | ✅ | ❌ | - |
testRuntimeOnly | 仅测试运行 | ❌ | ❌ | ✅ | ❌ | - |
annotationProcessor | 注解处理器(编译期) | - | - | - | ❌ | - |
developmentOnly | 开发时需要(DevTools) | - | ✅ | - | ❌ | - |
# implementation vs api(核心区别)
这是从 Maven 转 Gradle 最需要理解的概念:
implementation:依赖不会泄漏到下游模块的编译 classpath。下游模块看不到这个依赖的 API。api:依赖会泄漏到下游模块的编译 classpath。下游模块可以直接使用这个依赖的类。
模块 A → implementation(模块B) → 模块B的依赖C
模块 A 看不到 C 的类(编译时)
模块 A → api(模块B) → 模块B的依赖C
模块 A 能看到 C 的类(编译时)
2
3
4
5
选择原则:
| 场景 | 选择 |
|---|---|
| 依赖只在模块内部使用 | implementation(推荐,默认选择) |
| 依赖的类型出现在模块的公开 API 方法签名中 | api |
为什么默认用
implementation? 因为它能让 Gradle 更好地优化构建。当implementation依赖变化时,只有当前模块需要重新编译,下游模块不受影响。而api依赖变化时,所有下游模块都要重新编译。
# 实际项目示例
interview-guide 项目的依赖配置:
dependencies {
// implementation:主依赖,不暴露
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// runtimeOnly:运行时才需要(数据库驱动)
runtimeOnly 'org.postgresql:postgresql'
// compileOnly + annotationProcessor:Lombok
compileOnly libs.lombok
annotationProcessor libs.lombok
// testImplementation:测试依赖
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'com.h2database:h2'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Lombok + MapStruct 的配置
注解处理器需要特别注意顺序。interview-guide 项目中 Lombok 和 MapStruct 的配置:
// Lombok(先配置)
compileOnly libs.lombok
annotationProcessor libs.lombok
// MapStruct(必须在 Lombok 之后)
implementation "org.mapstruct:mapstruct:${libs.versions.mapstruct.get()}"
annotationProcessor "org.mapstruct:mapstruct-processor:${libs.versions.mapstruct.get()}"
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
2
3
4
5
6
7
8
lombok-mapstruct-binding确保 Lombok 生成的 getter/setter 能被 MapStruct 识别。顺序错误会导致 MapStruct 找不到 Lombok 生成的方法。
# Version Catalog(版本目录)
Version Catalog 是 Gradle 7+ 引入的依赖版本集中管理机制,用 TOML 文件统一声明所有依赖的版本,替代在 build.gradle 中散落的版本号。
类似 Maven 的
<dependencyManagement>+ BOM,但更直观、更易维护。
# 文件位置
项目根目录/
└── gradle/
└── libs.versions.toml # Version Catalog 文件
2
3
文件名
libs是默认的 Catalog 名称,在build.gradle中通过libs引用。Gradle 会自动识别gradle/目录下的*.versions.toml文件。
# 文件结构
Version Catalog 文件包含四个部分:
# 1. 版本号定义
[versions]
spring-boot = "4.1.0"
lombok = "1.18.46"
# 2. 依赖库定义
[libraries]
lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" }
tika-core = { module = "org.apache.tika:tika-core", version.ref = "tika" }
# 3. 插件定义
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
# 4. Bundle 定义(一组依赖打包引用)
[bundles]
tika = ["tika-core", "tika-parsers"]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 实际项目示例
interview-guide 项目的 gradle/libs.versions.toml:
[versions]
spring-boot = "4.1.0"
springAi = "2.0.0"
tika = "2.9.2"
lombok = "1.18.46"
junit-jupiter = "5.12.0"
redisson = "4.0.0"
mapstruct = "1.6.3"
aws-sdk = "2.29.51"
itext = "8.0.5"
pinyin4j = "2.5.0"
springdoc = "3.0.2"
[libraries]
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" }
tika-core = { module = "org.apache.tika:tika-core", version.ref = "tika" }
tika-parsers = { module = "org.apache.tika:tika-parsers-standard-package", version.ref = "tika" }
pinyin4j = { module = "com.belerweb:pinyin4j", version.ref = "pinyin4j" }
springdoc = { module = "org.springdoc:springdoc-openapi-starter-webmvc-ui", version.ref = "springdoc" }
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
spring-dependency-management = { id = "io.spring.dependency-management", version = "1.1.7" }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 在 build.gradle 中引用
// 引用依赖
dependencies {
implementation libs.lombok
implementation libs.tika.core // tika-core → tika.core(连字符转驼峰)
implementation libs.tika.parsers
implementation libs.springdoc
testImplementation libs.junit.jupiter
}
// 引用插件
plugins {
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
}
// 引用版本号
dependencies {
implementation "org.springframework.ai:spring-ai-starter-model-openai:${libs.versions.springAi.get()}"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 命名转换规则
Version Catalog 中的名称在 build.gradle 中引用时,遵循以下转换规则:
| TOML 中的名称 | 引用时的名称 | 规则 |
|---|---|---|
lombok | libs.lombok | 直接使用 |
tika-core | libs.tika.core | 连字符 - 转为 . 分隔 |
spring-boot | libs.spring.boot | 连字符 - 转为 . 分隔 |
junit-jupiter | libs.junit.jupiter | 连字符 - 转为 . 分隔 |
版本号引用:
libs.versions.springAi.get(),注意.get()是必须的(返回Provider<String>)。
# 版本号引用方式
[versions]
spring-boot = "4.1.0"
springAi = "2.0.0"
[libraries]
# 方式一:version.ref 引用上面定义的版本
spring-boot-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "spring-boot" }
# 方式二:直接写死版本
my-lib = { module = "com.example:my-lib", version = "1.0.0" }
# 方式三:不指定版本(由 BOM 或 dependency management 控制)
spring-ai-agent-utils = { module = "org.springaicommunity:spring-ai-agent-utils" }
2
3
4
5
6
7
8
9
10
11
12
13
# Bundle(依赖打包)
当一组依赖总是成对使用时,可以用 Bundle 打包:
[libraries]
tika-core = { module = "org.apache.tika:tika-core", version.ref = "tika" }
tika-parsers = { module = "org.apache.tika:tika-parsers-standard-package", version.ref = "tika" }
[bundles]
tika = ["tika-core", "tika-parsers"]
2
3
4
5
6
// 一次引入两个依赖
dependencies {
implementation libs.bundles.tika
}
2
3
4
# Version Catalog 的优势
| 对比项 | Maven dependencyManagement | Gradle Version Catalog |
|---|---|---|
| 文件格式 | XML(pom.xml 内) | TOML(独立文件) |
| 可读性 | 一般 | 好,结构清晰 |
| 类型安全 | 无 | 有(IDE 自动补全) |
| 多模块共享 | 父 POM 继承 | 自动对所有子项目可见 |
| 版本统一 | 是 | 是 |
# 排除依赖
# 排除单个依赖的传递依赖
dependencies {
implementation('com.alibaba:dashscope-sdk-java:2.22.7') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
}
2
3
4
5
interview-guide 项目排除了 DashScope SDK 自带的 slf4j-simple,使用 Spring Boot 的 Logback:
implementation('com.alibaba:dashscope-sdk-java:2.22.7') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
2
3
# 排除所有传递依赖
dependencies {
implementation('com.example:lib:1.0.0') {
transitive = false // 不拉取任何传递依赖
}
}
2
3
4
5
# 全局排除
在多模块项目中,可以在根 build.gradle 中全局排除:
allprojects {
configurations {
all {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
}
}
2
3
4
5
6
7
# 与 Maven 对比
Maven 排除依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.22.7</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
2
3
4
5
6
7
8
9
10
11
Gradle 排除依赖:
implementation('com.alibaba:dashscope-sdk-java:2.22.7') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
2
3
Gradle 的
exclude同样不需要指定版本号,只需group+module。
# BOM / Platform
# 什么是 BOM
BOM(Bill of Materials)是一个特殊的 POM,只声明依赖版本,不实际引入依赖。用于统一管理一组相关依赖的版本。
# Gradle 中的 BOM:platform
Gradle 用 platform() 引入 BOM:
dependencies {
// 引入 BOM,统一管理版本
implementation platform('org.springframework.boot:spring-boot-dependencies:4.1.0')
// 之后引用 BOM 管理的依赖时,无需指定版本
implementation 'org.springframework.boot:spring-boot-starter-web'
}
2
3
4
5
6
7
# Spring Boot 的依赖管理
Spring Boot 项目通常用 io.spring.dependency-management 插件来管理 BOM,效果与 platform() 类似:
plugins {
id 'org.springframework.boot'
id 'io.spring.dependency-management'
}
dependencies {
// 无需指定版本,由 spring-boot-dependencies BOM 管理
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
2
3
4
5
6
7
8
9
10
# 实际项目示例
interview-guide 项目同时使用了 BOM 和 Version Catalog:
dependencies {
// 引入 spring-ai-agent-utils BOM(版本对齐)
implementation platform(libs.spring.ai.agent.utils.bom)
// Spring AI 依赖(版本通过 Version Catalog 获取)
implementation "org.springframework.ai:spring-ai-starter-model-openai:${libs.versions.springAi.get()}"
implementation "org.springframework.ai:spring-ai-starter-vector-store-pgvector:${libs.versions.springAi.get()}"
// Testcontainers BOM
testImplementation platform('org.testcontainers:testcontainers-bom:2.0.5')
testImplementation 'org.testcontainers:testcontainers'
}
2
3
4
5
6
7
8
9
10
11
12
# platform vs enforcedPlatform
| 方式 | 说明 |
|---|---|
platform() | 软约束,BOM 中的版本可被覆盖 |
enforcedPlatform() | 硬约束,BOM 中的版本不可被覆盖 |
// 软约束:可以覆盖版本
implementation platform('org.springframework.boot:spring-boot-dependencies:4.1.0')
implementation 'org.postgresql:postgresql:42.7.0' // 覆盖 BOM 中的版本
// 硬约束:不可覆盖
enforcedPlatform('org.springframework.boot:spring-boot-dependencies:4.1.0')
implementation 'org.postgresql:postgresql' // 必须使用 BOM 中的版本
2
3
4
5
6
7
# 依赖冲突解决
# Gradle 的默认策略
Gradle 默认选择最高版本的依赖。当多个依赖引入同一库的不同版本时,Gradle 自动选择版本号最大的。
A → C:1.0
B → C:2.0
结果:使用 C:2.0
2
3
这与 Maven 的"路径优先"策略不同。Maven 选择层级最浅的版本,Gradle 选择版本号最高的。
# 查看依赖树
# 查看完整依赖树
gradlew dependencies
# 查看指定 configuration 的依赖
gradlew dependencies --configuration runtimeClasspath
# 查看依赖 Insight(某个依赖的来源)
gradlew dependencyInsight --dependency org.slf4j:slf4j-api --configuration runtimeClasspath
2
3
4
5
6
7
8
# 强制指定版本
dependencies {
// 强制使用指定版本
implementation('org.slf4j:slf4j-api') {
version {
strictly '2.0.9'
}
}
}
// 或全局强制
configurations.all {
resolutionStrategy {
force 'org.slf4j:slf4j-api:2.0.9'
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 统一版本
当多个依赖使用同一组版本时,可以用 resolutionStrategy 统一:
configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'org.slf4j') {
details.useVersion '2.0.9'
}
}
}
2
3
4
5
6
7
# 依赖分析命令
| 命令 | 说明 | Maven 对应 |
|---|---|---|
gradlew dependencies | 查看依赖树 | mvn dependency:tree |
gradlew dependencies --configuration runtimeClasspath | 查看指定配置的依赖 | - |
gradlew dependencyInsight --dependency <依赖> | 查看某依赖的来源 | mvn dependency:tree -Dincludes=... |
gradlew buildEnvironment | 查看插件依赖 | - |
# 完整依赖配置示例
以下是 interview-guide 项目依赖配置的结构概览:
dependencies {
// ===== Spring Boot Starters =====
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// ===== 运行时依赖 =====
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
// ===== BOM 引入 =====
implementation platform(libs.spring.ai.agent.utils.bom)
testImplementation platform('org.testcontainers:testcontainers-bom:2.0.5')
// ===== Version Catalog 引用 =====
implementation libs.tika.core
implementation libs.tika.parsers
implementation libs.springdoc
implementation libs.pinyin4j
// ===== 版本号引用 =====
implementation "org.springframework.ai:spring-ai-starter-model-openai:${libs.versions.springAi.get()}"
// ===== 排除传递依赖 =====
implementation('com.alibaba:dashscope-sdk-java:2.22.7') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
// ===== 注解处理器 =====
compileOnly libs.lombok
annotationProcessor libs.lombok
implementation "org.mapstruct:mapstruct:${libs.versions.mapstruct.get()}"
annotationProcessor "org.mapstruct:mapstruct-processor:${libs.versions.mapstruct.get()}"
// ===== 测试依赖 =====
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation libs.junit.jupiter
testRuntimeOnly 'com.h2database:h2'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39