5月27日 23:16
Gradle 依赖管理有哪些配置类型?如何解决冲突?
Gradle 通过 configurations(依赖配置)和 repositories(仓库)两大机制管理依赖。configurations 定义依赖的可见范围和生命周期,repositories 定义依赖的获取来源。
核心依赖配置类型
| 配置 | 编译时 | 运行时 | 传递给消费者 | 典型场景 |
|---|---|---|---|---|
| implementation | 可见 | 可见 | 不可见 | 默认选择,大多数依赖用这个 |
| api | 可见 | 可见 | 可见 | 库模块需要暴露给下游的 API 依赖 |
| compileOnly | 可见 | 不可见 | 不可见 | Lombok 等仅编译期需要的依赖 |
| runtimeOnly | 不可见 | 可见 | 不可见 | JDBC 驱动等仅运行时需要的依赖 |
| annotationProcessor | 可见 | 不可见 | 不可见 | 注解处理器 |
groovydependencies { implementation 'org.apache.commons:commons-lang3:3.12.0' api 'org.apache.commons:commons-math3:3.6.1' // 消费者也能访问 compileOnly 'org.projectlombok:lombok:1.18.24' // 编译后丢弃 runtimeOnly 'mysql:mysql-connector-java:8.0.28' // 运行时才加载 annotationProcessor 'org.projectlombok:lombok:1.18.24' }
implementation 与 api 的关键区别: implementation 的依赖不会出现在消费者的编译类路径中,改动后只重新编译当前模块;api 会传递,改动后消费者也要重新编译。优先用 implementation 可以显著缩短构建时间。
版本管理
推荐使用版本目录(Version Catalog),在 gradle/libs.versions.toml 中集中声明:
toml[versions] spring-boot = "3.0.0" [libraries] spring-boot-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
groovydependencies { implementation libs.spring.boot.web }
多模块项目也可用 BOM 统一版本:
groovydependencies { implementation platform('org.springframework.boot:spring-boot-dependencies:3.0.0') implementation 'org.springframework.boot:spring-boot-starter-web' // 版本由 BOM 控制 }
依赖冲突与排除
Gradle 默认取最高版本。当冲突不可自动解决时,可强制版本或排除:
groovy// 排除特定传递依赖 implementation('org.springframework.boot:spring-boot-starter-web:3.0.0') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } // 强制版本 configurations.all { resolutionStrategy { force 'org.apache.commons:commons-lang3:3.12.0' } }
查看依赖树排查冲突:./gradlew dependencies --configuration implementation
追问
Q: 为什么 implementation 改了不会触发下游模块重编译? A: implementation 的依赖被隔离在当前模块的编译类路径内,消费者编译时看不到这些依赖,因此改动不影响消费者的编译产物。这是 Gradle 3.4 引入 implementation 替代 compile 的核心动机。
Q: 什么时候必须用 api 而不能用 implementation? A: 当模块的公开 API 方法签名中用到了某个依赖的类型时(如返回值或参数类型来自该依赖),必须用 api,否则消费者编译时会找不到类。
Q: 动态版本(如 3.+)有什么问题?
A: 构建不可复现——同一份代码不同时间构建可能拉到不同版本,导致线上行为不一致。生产环境必须锁定版本。