1. 概述

Gradle 6.0 的发布带来了多项关键改进,显著提升了构建的效率与稳定性。核心升级包括:依赖管理增强、模块元数据发布支持、任务配置延迟(Configuration Avoidance)以及对 JDK 13 的完整支持。

本文将系统性地介绍 Gradle 6.0 中这些实用新特性。示例代码统一采用 Kotlin DSL 编写,更符合现代 Gradle 项目的实践。


2. 依赖管理增强

近年来 Gradle 持续优化依赖管理机制,而 Gradle 6.0 正是这些演进的集大成者。以下特性均已稳定,可放心在生产环境使用。

2.1 API 与实现分离

java-library 插件的核心价值在于强制区分 公开 API 依赖内部实现依赖。这能有效防止下游项目意外引用本应私有的类,从而提升构建稳定性。

虽然该插件早在 Gradle 3.4 就已引入,但其真正的威力在 Gradle 6.0 的完整依赖管理体系中才得以完全释放。

  • api: 声明的依赖会暴露给使用者(传递性依赖)
  • implementation: 仅项目内部使用,使用者不会继承
dependencies {
    api("com.fasterxml.jackson.core:jackson-databind:2.13.0") // 暴露给调用方
    implementation("org.apache.commons:commons-lang3:3.12.0") // 私有依赖
}

⚠️ 踩坑提醒:滥用 api 会导致依赖传递爆炸,应严格遵循“最小暴露”原则。

2.2 丰富的版本声明(Rich Versions)

当依赖树中出现版本冲突时,Gradle 6.0 允许通过精细化版本策略指导解析逻辑,避免“最新版本优先”带来的潜在不兼容问题。

核心指令:

  • require: 必须满足的最低版本
  • prefer: 优先选择的版本(无冲突时)
  • strictly: 严格限定版本范围
  • reject: 明确排除的版本
  • because: 添加注释说明(推荐)

场景示例:

你的项目使用 Guava,但仅依赖 10.0+ 的稳定 API,测试基于 28.1-jre。同时依赖的库 foo 强制使用 Guava 16.0。

dependencies {
    implementation("com.google.guava:guava") {
        version {
            require("10.0")
            prefer("28.1-jre")
            because("依赖 10.0+ 的 API,测试环境为 28.1-jre")
        }
    }
}

效果:当与 foo 冲突时,Gradle 会选择 16.0(满足双方要求),而非简单选最新版 28.1。

进阶用法:规避已知问题

dependencies {
    implementation("com.google.guava:guava") {
        version {
            strictly("[10.0, 28[")  // 严格限定 10.0 <= v < 28
            prefer("28.1-jre")
            reject("27.0")          // 已知 27.0 存在严重 Bug
            because("""
                API 在 10.0 引入,29.0 移除。27.0 版本有已知问题。
            """.trimIndent())
        }
    }
}

2.3 平台(Platforms)统一依赖版本

java-platform 插件类似于 Maven 的 <dependencyManagement>,用于集中管理一组依赖的版本号,避免多模块项目中版本不一致。

适用场景:

  • 多模块微服务项目
  • 统一技术栈(如 Spring Boot 版本)
  • 第三方组件版本对齐(如 HTTP 客户端)

创建平台项目 httpclient-platform

// build.gradle.kts
plugins {
    `java-platform`
}

dependencies {
    constraints {
        api("org.apache.httpcomponents:fluent-hc:4.5.10")
        api("org.apache.httpcomponents:httpclient:4.5.10")
    }
}

在业务模块中使用:

// build.gradle.kts
plugins {
    `java-library`
}

dependencies {
    api(platform(project(":httpclient-platform"))) // 引入平台
    implementation("org.apache.httpcomponents:fluent-hc") // 无需指定版本
}

优势:版本升级只需修改平台项目,所有子模块自动同步。

2.4 测试夹具(Test Fixtures)

Gradle 6.0 新增 java-test-fixtures 插件,允许将测试辅助代码(如基类、测试数据、Mock 对象)作为独立构件发布,无需创建额外的 *-test 库。

使用场景:

  • SPI(服务提供者接口)的契约测试
  • 通用测试工具类
  • 集成测试的公共配置

示例:为 Fibonacci 抽象定义测试夹具

  1. 创建 fibonacci-spi 项目: ```kotlin // build.gradle.kts plugins { java-library java-test-fixtures }

dependencies { testFixturesApi("org.junit.jupiter:junit-jupiter-api:5.8.1") testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.1") }


2. **编写测试夹具接口(位于 `src/testFixtures/java`):**
```java
public interface FibonacciSequenceGeneratorFixture {

    FibonacciSequenceGenerator provide();

    @Test
    default void whenSequenceIndexIsNegative_thenThrows() {
        FibonacciSequenceGenerator generator = provide();
        assertThrows(IllegalArgumentException.class, () -> generator.generate(-1));
    }

    @Test
    default void whenGivenIndex_thenGeneratesFibonacciNumber() {
        FibonacciSequenceGenerator generator = provide();
        int[] sequence = { 0, 1, 1, 2, 3, 5, 8 };
        for (int i = 0; i < sequence.length; i++) {
            assertEquals(sequence[i], generator.generate(i));
        }
    }
}
  1. 在实现项目 fibonacci-recursive 中复用:

    // build.gradle.kts
    dependencies {
     api(project(":fibonacci-spi"))
     testImplementation(testFixtures(project(":fibonacci-spi"))) // 关键:引用测试夹具
     testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
     testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
    }
    
  2. 直接使用夹具:

    class RecursiveFibonacciUnitTest implements FibonacciSequenceGeneratorFixture {
     @Override
     public FibonacciSequenceGenerator provide() {
         return new RecursiveFibonacci();
     }
    }
    

价值:大幅减少重复测试代码,提升测试一致性。


3. Gradle 模块元数据发布

传统 Maven/pom.xml 和 Ivy 格式无法存储 Gradle 6.0 的丰富依赖信息(如 rich versionsplatforms)。为解决此问题,Gradle 引入了 Gradle Module Metadata 规范。

核心要点:

  • ✅ 格式:JSON 文件(.module 后缀)
  • ✅ 兼容性:与 pom.xml 并存,不影响旧工具
  • ✅ 内容:完整保留 Gradle 特有的依赖元数据
  • ✅ 默认开启:使用新版 maven-publishivy-publish 插件时自动发布

发布到 Maven 仓库

// build.gradle.kts
plugins {
    `java-library`
    `maven-publish`
}

publishing {
    publications {
        create<MavenPublication>("mavenJava") {
            from(components["java"])
        }
    }
}

执行发布:

./gradlew publishToMavenLocal

查看本地仓库:

ls ~/.m2/repository/com/baeldung/gradle-6/1.0.0/
# 输出:
# gradle-6-1.0.0.jar
# gradle-6-1.0.0.module  # ✅ Gradle Module Metadata
# gradle-6-1.0.0.pom

⚠️ 注意:只有使用 Gradle 构建的项目才能消费 .module 文件中的增强元数据,Maven 项目仍只读 pom.xml


4. 任务配置避免(Configuration Avoidance)

Gradle 构建的性能瓶颈常在于 任务配置阶段(即解析 build.gradle 时创建和配置所有任务)。Gradle 5.1 引入的 Configuration Avoidance API 在 6.0 正式稳定。

核心思想

延迟任务/配置的实例化,直到真正需要执行时才“实现”(realize),从而跳过大量无用配置。

迁移指南(关键替换)

旧写法 (立即配置) 新写法 (延迟配置) 优势
tasks.create() tasks.register() 任务未执行时不创建实例
tasks.getByName() tasks.named() 返回 Provider<Task>,延迟获取
configurations.create() configurations.register() 延迟配置创建
File(project.buildDir, "foo") project.layout.buildDirectory.dir("foo") 延迟路径解析

示例:注册延迟任务

val copyExtraLibs by tasks.registering(Copy::class) {
    from("src/extralibs")
    into(layout.buildDirectory.dir("extra-libs"))
}
  • registering 返回 TaskProvider<Copy>
  • Copy 实例在任务真正执行前不会被创建
  • from/into 的配置闭包也延迟执行

效果:大型多模块项目构建脚本解析时间显著缩短。


5. JDK 13 支持

Gradle 6.0 正式支持使用 JDK 13 编译和运行项目。

基础配置

java {
    sourceCompatibility = JavaVersion.VERSION_13
    targetCompatibility = JavaVersion.VERSION_13
}

启用预览特性(Preview Features)

JDK 13 包含预览特性(如 Raw String Literals),需显式开启:

tasks {
    compileJava {
        options.compilerArgs.add("--enable-preview")
    }
    
    test {
        jvmArgs("--enable-preview")
    }
    
    javadoc {
        (options as CoreJavadocOptions).apply {
            addStringOption("source", "13")
            addBooleanOption("-enable-preview", true)
        }
    }
}

⚠️ 警告:预览特性不保证向后兼容,生产环境慎用。


6. 总结

Gradle 6.0 是一次以 构建稳定性性能 为核心的升级:

  • 依赖管理:通过 rich versionsplatforms 精细化控制依赖解析。
  • 元数据发布.module 文件让下游 Gradle 项目能继承完整依赖策略。
  • 配置避免register 等 API 显著优化大型项目的构建性能。
  • JDK 支持:无缝对接 JDK 13,包括预览特性。

这些特性共同构成了现代 Gradle 项目的最佳实践基础。建议新项目直接采用,存量项目可逐步迁移。

本文示例代码详见 GitHub: https://github.com/baeldung/tutorials/tree/master/gradle-modules/gradle-6


原始标题:What’s New in Gradle 6.0 | Baeldung

« 上一篇: Java Weekly, 第319期
» 下一篇: Java Text Blocks 详解