2. 依赖类型详解:compileOnly、runtimeOnly、testImplementation、annotationProcessor、provided
Gradle 的依赖配置(dependencies 块)通过声明不同的“配置”控制依赖在构建生命周期中的可见范围。理解每种配置的作用域是管理版本冲突、减小构建产物体积、避免运行时错误的基石。本章逐一拆解 compileOnly、runtimeOnly、testImplementation、annotationProcessor 以及 provided(Gradle 中的等效配置),并给出实际选择指南。
2.1 compileOnly — 编译期可见,运行时排除
原理: 依赖仅添加到编译类路径,不会打包到最终产物(JAR/WAR)中,也不会出现在运行时类路径。常用于 Servlet API、Lombok 注解处理器、编译期库。
配置示例:
dependencies {
compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
compileOnly 'org.projectlombok:lombok:1.18.30'
}
compileOnly 用于必须在运行时存在的依赖,例如数据库驱动。编译通过但运行时报 ClassNotFoundException。2.2 runtimeOnly — 运行时可见,编译不可见
原理: 依赖不参与编译,仅在运行时(以及测试运行时)包含。典型代表是日志实现(如 Logback)、JDBC 驱动。编译时只需接口(如 SLF4J API),运行时才需要具体实现。
dependencies {
implementation 'org.slf4j:slf4j-api:2.0.9'
runtimeOnly 'ch.qos.logback:logback-classic:1.4.14'
}
gradle dependencies --configuration runtimeClasspath 可查看运行时所有依赖树,确认是否有遗漏的 runtimeOnly 依赖。2.3 testImplementation — 测试专属依赖
原理: 依赖仅在编译和执行测试时生效,不影响生产代码的编译和运行。用于 JUnit、Mockito、AssertJ 等测试框架。
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
testImplementation 'org.mockito:mockito-core:5.4.0'
}
注意: 测试类路径继承自 implementation 和 compileOnly(取决于具体配置链),但 testImplementation 不会反向传播到生产代码。
2.4 annotationProcessor — 注解处理器专用配置
原理: Gradle 从 4.6 开始引入独立配置,将注解处理器(如 Lombok、MapStruct、Dagger、Glide 等)与其依赖分离,避免处理器 jar 被意外打包进最终产物。它仅在编译期生效,参与注解处理流程。
dependencies {
annotationProcessor 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
}
annotationProcessor 配置中,可避免增量编译时重新处理全部类;Gradle 增量处理器会缓存处理器类路径。2.5 provided(War 插件中的 providedCompile)
原理: 在纯 Java 库中,provided 不是标准配置。但在 War 插件中,providedCompile 等效于 compileOnly + testCompileClasspath,即编译和测试阶段可用,但不会打包到 WAR 的 WEB-INF/lib。在普通 Java 插件中若要达到“编译可见、运行排除”效果,直接使用 compileOnly。
plugins {
id 'war'
}
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:4.0.1'
// 等价于 compileOnly + testImplementation(仅测试编译)
}
provided 配置(由某些插件提供),应统一改为 compileOnly 或 providedCompile(若使用 War 插件),并清理冗余依赖。2.6 选择矩阵与常见陷阱
| 配置 | 编译类路径 | 运行时类路径 | 测试类路径 | 产物打包 | 典型场景 |
|---|---|---|---|---|---|
compileOnly |
✓ | ✗ | ✗ | ✗ | Servlet API、Lombok |
runtimeOnly |
✗ | ✓ | ✓ | ✓ | 日志实现、JDBC 驱动 |
testImplementation |
✗ | ✗ | ✓ | ✗ | JUnit、Mockito |
annotationProcessor |
✓ (仅处理阶段) | ✗ | ✓ (仅处理阶段) | ✗ | Lombok 处理器 |
providedCompile (war) |
✓ | ✗ | ✓ | ✗ | Servlet API + 测试需要 |
2.7 调试与验证方法
- 查看依赖报告
gradle dependencies --configuration compileClasspath gradle dependencies --configuration runtimeClasspath - 确认是否打入产物
jar tf build/libs/your-app.jar | grep -i 'driver\|lombok\|servlet' - 运行时测试:编写一个使用
compileOnly依赖的测试,在生产环境部署并启动,观察是否缺失类。 - 注解处理器失效:若 Lombok 未生效,检查是否错误地将
annotationProcessor写成了compileOnly或implementation。
build.gradle 顶部添加注释块,明确声明每类依赖的作用域,便于团队维护。例如:// ===== 编译期提供,运行时由容器提供 =====
compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
// ===== 运行时驱动,编译时仅用接口 =====
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.1.0'
runtimeOnly 'com.mysql:mysql-connector-j:8.1.0'
// ===== 测试框架 =====
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
// ===== 注解处理器 =====
annotationProcessor 'org.projectlombok:lombok:1.18.30'
性能/稳定性提示: 避免在 compileOnly 中引入过大 jar(如完整 Spring Boot starter),否则会拖慢编译速度且无运行时价值。使用 runtimeOnly 时注意版本冲突,若多个 runtimeOnly 依赖传递了不同版本的同一库,运行时可能产生 NoSuchMethodError,建议统一管理版本(参考第 5 章版本对齐策略)。