Gradle全面指南:从入门到精通

这是一份非常详细、实用、通俗易懂、权威且全面的 Gradle 全面指南。


目录

  1. Gradle 是什么?为什么选择 Gradle?
    • 1.1 构建工具的概念
    • 1.2 Gradle 的核心优势
    • 1.3 Gradle vs Maven vs Ant
  2. Gradle 基础概念
    • 2.1 安装与配置
      • 2.1.1 安装 SDKMAN! (推荐)
      • 2.1.2 手动安装
      • 2.1.3 环境变量配置 (GRADLE_HOME, PATH)
      • 2.1.4 验证安装 (gradle -v)
    • 2.2 项目结构 (约定优于配置)
      • 2.2.1 settings.gradle(.kts) 文件
      • 2.2.2 build.gradle(.kts) 文件
      • 2.2.3 源集目录 (src/main, src/test)
    • 2.3 Gradle Wrapper (gradlew, gradlew.bat)
      • 2.3.1 是什么?为什么重要?
      • 2.3.2 生成 Wrapper (gradle wrapper)
      • 2.3.3 使用 Wrapper (./gradlew <task>)
    • 2.4 任务 (Task)
      • 2.4.1 任务定义 (task / tasks.register)
      • 2.4.2 任务类型 (Copy, Delete, JavaCompile, Exec 等)
      • 2.4.3 任务配置 (闭包 / doFirst, doLast)
      • 2.4.4 任务依赖 (dependsOn)
      • 2.4.5 任务输入输出 (inputs, outputs)
    • 2.5 依赖管理 (Dependencies)
      • 2.5.1 依赖仓库 (repositories)
      • 2.5.2 依赖声明 (dependencies)
      • 2.5.3 依赖配置 (implementation, api, compileOnly, runtimeOnly, testImplementation 等)
      • 2.5.4 依赖版本管理 (versions.toml, 变量)
      • 2.5.5 依赖冲突解决
    • 2.6 插件 (Plugins)
      • 2.6.1 核心插件 (java, application, war)
      • 2.6.2 社区插件 (com.android.application, org.springframework.boot)
      • 2.6.3 插件应用 (plugins {} / apply plugin:)
      • 2.6.4 插件配置 (闭包)
    • 2.7 构建生命周期 (Build Lifecycle)
      • 2.7.1 初始化阶段 (settings.gradle)
      • 2.7.2 配置阶段 (build.gradle)
      • 2.7.3 执行阶段 (gradle <task>)
  3. Gradle 脚本编写 (DSL)
    • 3.1 Groovy DSL vs Kotlin DSL (KTS)
    • 3.2 基本语法 (变量、方法、闭包)
    • 3.3 项目与任务 API (project, task)
    • 3.4 依赖管理 API (dependencies, configurations)
    • 3.5 扩展属性 (ext, extra)
    • 3.6 多项目构建 (include, project)
    • 3.7 增量构建 (up-to-date 检查)
    • 3.8 构建缓存 (本地、远程)
    • 3.9 编写自定义任务类型
    • 3.10 编写自定义插件
      • 3.10.1 插件 ID (gradlePlugin)
      • 3.10.2 插件实现类 (Plugin)
      • 3.10.3 扩展对象 (Extension)
      • 3.10.4 发布到本地或仓库
  4. Gradle 最佳实践
    • 4.1 优先使用 Kotlin DSL (KTS)
    • 4.2 充分利用 Gradle Wrapper
    • 4.3 保持构建脚本简洁、可读
    • 4.4 使用明确的依赖配置
    • 4.5 管理依赖版本 (使用 versions.tomlextra 属性)
    • 4.6 编写可缓存的任务 (定义 inputs/outputs)
    • 4.7 利用构建缓存
    • 4.8 使用 buildSrccomposite builds 管理插件和共享逻辑
    • 4.9 编写测试
    • 4.10 性能调优 (--profile, --scan, --dry-run)
    • 4.11 安全性 (dependency verification)
  5. Gradle 与 IDE 集成
    • 5.1 IntelliJ IDEA / Android Studio
      • 5.1.1 导入 Gradle 项目
      • 5.1.2 运行 Gradle 任务
      • 5.1.3 调试构建脚本
    • 5.2 Eclipse
      • 5.2.1 Buildship 插件
      • 5.2.2 导入和运行
  6. Gradle 高级主题
    • 6.1 响应式 API (Provider, Property)
    • 6.2 惰性配置 (Lazy Configuration)
    • 6.3 配置缓存 (Configuration Cache)
    • 6.4 自定义源集 (Source Sets)
    • 6.5 构建变体 (Variants - Android, Native)
    • 6.6 构建扫描 (--scan)
    • 6.7 持续集成集成 (Jenkins, GitLab CI, GitHub Actions)
    • 6.8 发布工件到仓库 (maven-publish, ivy-publish)
  7. 完整实战案例
    • 案例 1:构建一个简单的 Java 应用程序
      • 7.1.1 项目结构与设置
      • 7.1.2 build.gradle.kts 详解 (应用 application 插件)
      • 7.1.3 定义主类
      • 7.1.4 添加依赖 (JUnit)
      • 7.1.5 编写测试
      • 7.1.6 运行任务 (run, test, jar, distZip)
      • 7.1.7 完整可运行代码
    • 案例 2:构建一个多模块项目 (Java Library + Web Application)
      • 7.2.1 项目结构 (settings.gradle.kts)
      • 7.2.2 core 模块 (Java Library)
      • 7.2.3 web 模块 (War Application, 依赖 core)
      • 7.2.4 共享依赖版本管理 (gradle.propertiesbuildSrc)
      • 7.2.5 定义根项目任务 (build, clean)
      • 7.2.6 完整可运行代码
    • 案例 3:编写一个自定义 Gradle 插件 (Kotlin)
      • 7.3.1 创建插件项目 (build.gradle.kts 应用 java-gradle-plugin)
      • 7.3.2 定义插件 ID (gradlePlugin)
      • 7.3.3 实现插件逻辑 (GenerateVersionFilePlugin)
      • 7.3.4 定义扩展 (VersionExtension)
      • 7.3.5 创建自定义任务 (GenerateVersionFileTask)
      • 7.3.6 在插件中注册任务
      • 7.3.7 发布到本地 Maven 仓库 (maven-publish)
      • 7.3.8 在另一个项目中应用自定义插件
      • 7.3.9 完整可运行代码
  8. 总结与资源
    • 8.1 Gradle 官方文档
    • 8.2 Gradle 社区论坛
    • 8.3 书籍推荐
    • 8.4 持续学习

1. Gradle 是什么?为什么选择 Gradle?

1.1 构建工具的概念 想象一下你开发软件的过程:你需要编译源代码、运行测试、打包成可部署的格式(如 JAR, WAR, APK)、管理项目依赖的第三方库、生成文档、部署到服务器等等。手动完成这些步骤不仅繁琐、容易出错,而且在大型项目或多人协作时几乎不可能高效完成。

构建工具(Build Tool)就是用来自动化这些重复性开发任务的软件。它们允许你通过编写脚本(通常是基于特定领域语言 DSL)来定义构建过程。当你运行构建命令时,工具会按照脚本的指示,按顺序执行编译、测试、打包等一系列操作,最终生成所需的软件产物。

1.2 Gradle 的核心优势 Gradle 是一个开源的、功能强大的构建自动化工具。它结合了之前工具(如 Apache Ant 和 Maven)的优点,并引入了许多创新的特性:

  • 灵活性 (Flexibility): Gradle 不强制使用固定的项目结构或约定。它提供了一个通用的核心模型,允许你通过 DSL 或 API 精确地定义几乎任何类型的构建过程。你可以轻松定制任务逻辑。
  • 基于约定 (Convention over Configuration): 虽然灵活,但 Gradle 为常见项目类型(如 Java, Android)提供了智能的默认设置和约定(如源文件位置)。你可以轻松开始,并在需要时覆盖约定。
  • 高性能 (Performance): Gradle 采用了多项优化技术:
    • 增量构建 (Incremental Builds): Gradle 跟踪任务的输入和输出。如果输入没有变化且输出存在,任务会被标记为 UP-TO-DATE 并跳过执行。只执行必要的任务。
    • 构建缓存 (Build Cache): Gradle 可以缓存任务的输出(本地或远程)。当另一个构建(可能在另一台机器上)需要相同的输出时,可以直接从缓存中获取,避免重复计算。
    • 并行执行 (Parallel Execution): Gradle 可以在有依赖关系的任务之间并行执行独立的任务链。
    • 配置缓存 (Configuration Cache - 实验性/稳定中): Gradle 可以缓存构建脚本的配置结果。对于后续构建,如果脚本没有变化,它可以跳过配置阶段直接进入执行阶段,大幅提升构建速度。
  • 强大的依赖管理 (Dependency Management): Gradle 内置了强大的依赖管理引擎。它支持从 Maven, Ivy 等仓库下载库文件,并能精确处理传递依赖和解决冲突。依赖配置(如 implementation, api) 提供了清晰的依赖作用域控制。
  • 可扩展性 (Extensibility): 你可以轻松编写自己的 Gradle 插件和任务类型来扩展功能。庞大的社区提供了成千上万的插件,覆盖了从 Android 开发到文档生成的广泛领域。
  • 多语言支持 (Multi-Language): Gradle 最初主要服务于 JVM 生态(Java, Kotlin, Groovy, Scala),但现在也支持构建 C++, Python, Android, iOS 等多种平台和语言的项目。
  • 现代 DSL (DSL): Gradle 提供了两种主要的 DSL:Groovy DSL (语法简洁,动态类型)和 Kotlin DSL(静态类型,IDE 支持更好,类型安全)。Kotlin DSL 正成为官方推荐和社区偏好的选择。
  • Gradle Wrapper: 这是一个确保项目使用特定 Gradle 版本运行的工具,解决了开发者和 CI 服务器环境配置不一致的问题。

1.3 Gradle vs Maven vs Ant

  • Apache Ant: 最早的流行构建工具之一。它基于 XML 配置,使用 目标(target)任务(task)。Ant 非常灵活,但缺乏依赖管理(需配合 Ivy)和项目结构约定,大型项目配置可能变得冗长复杂。
  • Apache Maven: 引入了 约定优于配置 和强大的 依赖管理 ,使用 项目对象模型(POM) XML 文件。Maven 的生命周期和插件机制提供了标准化。然而,其 XML 配置有时显得冗长,自定义复杂逻辑相对困难,扩展性不如 Gradle。
  • Gradle: 融合了 Ant 的灵活性和 Maven 的约定/依赖管理优势。它使用更简洁、表达能力更强的 Groovy/Kotlin DSL。增量构建、缓存机制使其性能优异。其插件模型极其强大且易于扩展。Gradle 正在成为许多领域(尤其是 Android、Kotlin 生态)的事实标准。

总结: Gradle 凭借其灵活性、高性能、强大的依赖管理、优秀的扩展性以及现代化的 DSL,成为了当今构建工具领域的领先者。


2. Gradle 基础概念

2.1 安装与配置

2.1.1 安装 SDKMAN! (推荐) SDKMAN! 是一个管理多个 SDK 版本的工具,非常适合安装和管理 Gradle。

bash 复制代码
# 安装 SDKMAN!
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

# 列出可用的 Gradle 版本
sdk list gradle

# 安装特定版本的 Gradle (例如 8.5)
sdk install gradle 8.5

# 设置默认版本
sdk default gradle 8.5

2.1.2 手动安装

  1. 访问 Gradle 官网下载页面
  2. 下载你需要的版本(通常是完整的二进制分发版,如 gradle-8.5-bin.zip)。
  3. 解压下载的文件到你选择的目录(例如 /opt/gradleC:\Gradle)。

2.1.3 环境变量配置 (GRADLE_HOME, PATH)

  • Linux/macOS:

    bash 复制代码
    # 编辑 ~/.bashrc 或 ~/.zshrc
    export GRADLE_HOME=/path/to/gradle # 例如 /opt/gradle/gradle-8.5
    export PATH=$PATH:$GRADLE_HOME/bin
    
    # 使配置生效
    source ~/.bashrc # 或 source ~/.zshrc
  • Windows:

    1. 右键点击"此电脑" -> "属性" -> "高级系统设置" -> "环境变量"。
    2. 在"系统变量"下,点击"新建":
      • 变量名:GRADLE_HOME
      • 变量值:Gradle 解压目录(例如 C:\Gradle\gradle-8.5
    3. 在"系统变量"中找到 Path 变量,点击"编辑"。
    4. 点击"新建",添加 %GRADLE_HOME%\bin
    5. 点击"确定"保存所有更改。

2.1.4 验证安装 (gradle -v) 打开一个新的终端/命令提示符窗口,运行:

bash 复制代码
gradle -v

如果安装成功,你将看到 Gradle 的版本信息、Groovy 版本、Kotlin DSL 版本、JVM 信息等。

2.2 项目结构 (约定优于配置) 一个标准的 Gradle 项目通常包含以下文件和目录:

复制代码
my-project/
├── build.gradle(.kts)      # 主构建脚本 (Groovy 或 Kotlin)
├── settings.gradle(.kts)   # 项目设置脚本 (定义项目名称、包含的子模块)
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar     # Wrapper 核心 JAR
│       └── gradle-wrapper.properties # Wrapper 配置 (指定 Gradle 版本)
├── gradlew                  # Unix/Linux Wrapper 脚本
├── gradlew.bat              # Windows Wrapper 脚本
└── src/
    ├── main/                # 主源代码
    │   ├── java/            # Java 主源码
    │   ├── kotlin/          # Kotlin 主源码
    │   ├── resources/       # 主资源文件 (配置文件、图片等)
    │   └── webapp/          # Web 应用资源 (可选, 如 WAR 项目)
    └── test/                # 测试源代码
        ├── java/            # Java 测试源码
        ├── kotlin/          # Kotlin 测试源码
        └── resources/       # 测试资源文件
  • settings.gradle(.kts) 文件: 这是构建过程的入口点。它定义了哪些项目参与此次构建(对于单项目构建,它通常只定义根项目名称;对于多项目构建,它使用 includeincludeBuild 来包含子项目或组合构建)。
  • build.gradle(.kts) 文件: 这是项目的主要构建脚本。它应用插件、配置项目、定义任务、声明依赖等。
  • 源集目录 (src/main, src/test): 这些是 Gradle 为 Java 和许多其他插件定义的默认源代码位置。你可以根据需要配置自定义源集。

2.3 Gradle Wrapper (gradlew, gradlew.bat)

2.3.1 是什么?为什么重要? Gradle Wrapper(简称 Wrapper)是 Gradle 项目的一部分。它由几个文件组成:

  • gradlew (Unix shell script)
  • gradlew.bat (Windows batch script)
  • gradle/wrapper/gradle-wrapper.jar (Wrapper 的 JAR 文件)
  • gradle/wrapper/gradle-wrapper.properties (配置文件,指定使用哪个 Gradle 版本)

重要性:

  • 版本一致性: 确保项目使用的 Gradle 版本被固定下来。无论开发者本地安装了哪个 Gradle 版本,或者 CI 服务器上安装了哪个版本,项目都将使用 Wrapper 配置中指定的特定版本进行构建。避免了"在我机器上是好的"问题。
  • 零安装: 新加入项目的开发者不需要手动安装 Gradle。只需检出代码仓库,运行 Wrapper 脚本 (./gradlewgradlew.bat),Wrapper 会自动下载并安装指定版本的 Gradle(如果尚未安装)。

2.3.2 生成 Wrapper (gradle wrapper) 在项目根目录下,运行:

bash 复制代码
gradle wrapper --gradle-version 8.5 --distribution-type bin
  • --gradle-version: 指定你希望 Wrapper 使用的 Gradle 版本。
  • --distribution-type: bin (只包含运行时) 或 all (包含源码和文档)。通常 bin 足够。 运行此命令后,项目中会增加 gradlew, gradlew.bat, gradle/wrapper/ 目录及其内容。

2.3.3 使用 Wrapper (./gradlew <task>)

  • Linux/macOS 终端中:

    bash 复制代码
    ./gradlew clean build
  • Windows 命令提示符或 PowerShell 中:

    bash 复制代码
    gradlew.bat clean build

    (在 PowerShell 中,你可能需要 .\gradlew.bat 或配置执行策略 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser)

2.4 任务 (Task) 任务是 Gradle 构建工作的基本单元。每个任务代表构建过程中的一个原子操作,例如编译一些类、复制文件、运行测试、打包 JAR 等。

2.4.1 任务定义 (task / tasks.register) 在构建脚本中定义任务:

  • Groovy DSL:

    groovy 复制代码
    task myTask { // 旧方式 (仍可用)
        group = 'Custom' // 可选,任务分组
        description = 'This is my custom task' // 可选,任务描述
        doLast { // 任务执行时的动作
            println 'Hello from myTask!'
        }
    }
    
    tasks.register('myNewTask') { // 推荐方式 (惰性注册)
        group = 'Custom'
        description = 'This is my new task'
        doLast {
            println 'Hello from myNewTask!'
        }
    }
  • Kotlin DSL (KTS):

    kotlin 复制代码
    // tasks 是 TaskContainer
    tasks.register("myTask") { // 使用 register (惰性注册)
        group = "Custom"
        description = "This is my custom task"
        doLast { // 任务执行时的动作
            println("Hello from myTask!")
        }
    }
    
    // 旧方式 (不推荐, 因为会在配置阶段立即执行闭包)
    tasks.create("myOldTask") {
        doLast {
            println("Hello from myOldTask!")
        }
    }

惰性注册 (register) vs 立即创建 (create/旧 task): register 方法在配置阶段只注册任务,其配置闭包会在任务真正需要执行时才被计算(惰性求值)。这有助于提高配置性能,尤其是在任务数量多或配置复杂时。create 和旧的 task 语法会在配置阶段立即执行闭包。

2.4.2 任务类型 (Copy, Delete, JavaCompile, Exec 等) Gradle 提供了许多预定义的任务类型,封装了常见操作。使用类型可以带来额外的类型安全性和便利的方法:

kotlin 复制代码
// Kotlin DSL
tasks.register<Copy>("copyFiles") {
    from("src/main/resources") // 源目录
    into("build/output")       // 目标目录
    include("*.properties")    // 包含的文件模式
}

tasks.register<Delete>("cleanOutput") {
    delete("build/output")
}

tasks.register<Exec>("runScript") {
    commandLine("python", "myscript.py")
}

2.4.3 任务配置 (闭包 / doFirst, doLast) 任务可以配置其属性,并定义在任务执行时要执行的动作。

  • 配置闭包: 在任务注册或创建时提供的闭包主要用于配置任务的属性(如 group, description, inputs, outputs)和添加动作。
  • 动作 (doFirst, doLast): 这些方法用于定义任务执行时实际要做的事情。doLast 中的动作会在任务执行阶段最后执行(最常见)。doFirst 中的动作会在任务执行阶段最先执行。一个任务可以有多个 doFirstdoLast 动作,它们按添加顺序执行。
kotlin 复制代码
tasks.register("complexTask") {
    // 配置阶段:设置属性
    val message = "Result: "
    outputs.dir("build/results")

    // 执行阶段:添加动作
    doFirst {
        println("Starting complexTask...")
    }
    doLast {
        val result = calculateResult() // 假设的函数
        println("$message $result")
        file("build/results/out.txt").writeText(result.toString())
    }
}

2.4.4 任务依赖 (dependsOn) 任务通常不是孤立的,它们之间存在依赖关系。例如,编译任务 (compileJava) 需要在测试任务 (test) 之前运行,因为测试需要编译好的类文件。

kotlin 复制代码
tasks.register("taskB") {
    dependsOn("taskA") // taskB 依赖于 taskA
    doLast {
        println("TaskB runs after TaskA")
    }
}

tasks.register("taskA") {
    doLast {
        println("TaskA")
    }
}

运行 gradle taskB 会先执行 taskA,再执行 taskB。依赖可以是任务名称、任务对象或任务集合。

2.4.5 任务输入输出 (inputs, outputs) 这是 Gradle 实现增量构建和缓存的核心机制。任务应该声明其输入(任务执行所依赖的东西)和输出(任务执行产生的东西)。

  • 输入 (inputs): 可以是文件、目录、属性值。如果输入没有变化,且输出存在,则任务被认为是 UP-TO-DATE 并被跳过。
  • 输出 (outputs): 通常是任务生成的文件或目录。Gradle 根据输出文件的时间戳和内容来检查任务是否需要重新运行。
kotlin 复制代码
tasks.register<ProcessTemplates>("processTemplates") {
    // 输入:模板文件和模板引擎版本
    inputs.files(fileTree("src/main/templates"))
    inputs.property("engineVersion", "1.2.3")

    // 输出:处理后的文件目录
    outputs.dir("build/processed")
    // ... 任务实现逻辑 ...
}

定义明确的输入输出是编写高效、可缓存任务的关键。

2.5 依赖管理 (Dependencies) 现代软件项目几乎都依赖外部库。Gradle 提供了强大的机制来声明、解析和管理这些依赖。

2.5.1 依赖仓库 (repositories) 依赖仓库是存放库文件(JAR, AAR, POM 等)的地方。Gradle 需要知道从哪里下载这些库。

kotlin 复制代码
repositories {
    mavenCentral() // 最常用的公共 Maven 仓库
    // Maven Local (本地 Maven 仓库 ~/.m2/repository)
    mavenLocal()
    // 其他公共仓库
    maven {
        url = uri("https://repo.spring.io/milestone")
    }
    // 公司私有仓库 (需要认证时)
    maven {
        url = uri("https://mycompany.com/repo")
        credentials {
            username = "user"
            password = "pass"
        }
    }
    // Ivy 仓库
    ivy {
        url = uri("https://myivy.com/repo")
        patternLayout {
            artifact("[organisation]/[module]/[revision]/[type]/[artifact].[ext]")
        }
    }
}

2.5.2 依赖声明 (dependencies)dependencies {} 块中声明项目所需的依赖。

kotlin 复制代码
dependencies {
    // 声明一个依赖 (implementation 是配置名称)
    implementation("org.springframework.boot:spring-boot-starter-web:3.1.0")
    // 简写形式 group:artifact:version
    implementation("com.google.guava:guava:31.1-jre")
    // 依赖本地文件
    implementation(files("libs/my-local-lib.jar"))
    // 依赖其他项目 (多项目构建中)
    implementation(project(":core-module"))
}

2.5.3 依赖配置 (implementation, api, compileOnly, runtimeOnly, testImplementation 等) 依赖配置定义了依赖的作用域和可见性。它们决定了:

  • 依赖在哪些类路径上可用(编译、运行时、测试)。
  • 依赖是否会被传递给依赖于当前项目的其他项目(传递性)。 常见的配置(由 Java 插件提供):
  • implementation: 编译和运行时需要,但不会 暴露给使用此项目的其他项目。推荐用于绝大多数依赖。 避免不必要的传递依赖泄露。
  • api: 编译和运行时需要,并且暴露给使用此项目的其他项目。用于那些构成项目公共 API 一部分的依赖。
  • compileOnly: 只在编译时需要,运行时不需要。常用于注解处理器等。
  • runtimeOnly: 只在运行时需要,编译时不需要。
  • testImplementation: 只在测试的编译和运行时需要。
  • testCompileOnly: 只在测试的编译时需要。
  • testRuntimeOnly: 只在测试的运行时需要。 Android 插件等还会提供更多特定配置。

2.5.4 依赖版本管理 (versions.toml, 变量) 为了集中管理依赖版本,避免在多个地方重复版本号:

  • 使用 extra 属性或变量 (Groovy):

    groovy 复制代码
    ext {
        springBootVersion = "3.1.0"
        guavaVersion = "31.1-jre"
    }
    
    dependencies {
        implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion"
        implementation "com.google.guava:guava:$guavaVersion"
    }
  • 使用 Kotlin DSL 的 val (KTS):

    kotlin 复制代码
    val springBootVersion by extra("3.1.0")
    val guavaVersion by extra("31.1-jre")
    
    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
        implementation("com.google.guava:guava:$guavaVersion")
    }
  • 使用 libs.versions.toml (官方推荐 - Catalog): Gradle 7.0+ 引入了版本目录 (Version Catalog)。

    1. gradle 目录下创建 libs.versions.toml 文件:

      toml 复制代码
      [versions]
      spring-boot = "3.1.0"
      guava = "31.1-jre"
      
      [libraries]
      spring-boot-starter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web", version.ref = "spring-boot" }
      guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
    2. build.gradle.kts 中使用:

      kotlin 复制代码
      dependencies {
          implementation(libs.spring.boot.starter.web) // 类型安全访问器
          implementation(libs.guava)
      }

    版本目录提供了更好的集中管理、类型安全和 IDE 支持。

2.5.5 依赖冲突解决 当多个依赖(直接或传递)引用了同一个库的不同版本时,就会发生依赖冲突。Gradle 默认会选择最新版本。你可以:

  • 查看依赖树: gradle dependenciesgradle :module:dependencies

  • 强制指定版本:

    kotlin 复制代码
    configurations.all {
        resolutionStrategy {
            force("com.google.guava:guava:31.1-jre") // 强制使用此版本
        }
    }
  • 排除特定依赖:

    kotlin 复制代码
    dependencies {
        implementation("org.apache.logging.log4j:log4j-core:2.17.2") {
            exclude(group = "com.fasterxml.jackson.core") // 排除特定 group
            // exclude(group: "com.fasterxml.jackson.core", module: "jackson-databind")
        }
    }
  • 使用 dependencyInsight: gradle dependencyInsight --dependency guava 帮助分析特定依赖的来源。

2.6 插件 (Plugins) 插件是 Gradle 扩展其核心功能的主要方式。它们可以:

  • 添加新的任务类型(如 JavaCompile, Test)。
  • 配置项目的默认约定(如源集位置)。
  • 添加新的依赖配置。
  • 集成其他工具。

2.6.1 核心插件 (java, application, war) Gradle 自带了许多核心插件:

  • java: 提供 Java 项目的基本构建能力(编译、测试、打包 JAR)。
  • application: 构建可执行的 Java 应用程序(包含 run 任务和分发任务)。
  • war: 构建 Web 应用程序 (WAR) 文件。
  • maven-publish, ivy-publish: 发布项目到 Maven 或 Ivy 仓库。
  • java-library: 比 java 插件更适合构建供其他项目使用的库(区分 apiimplementation)。

2.6.2 社区插件 (com.android.application, org.springframework.boot) 庞大的社区提供了海量插件:

  • com.android.application, com.android.library: 用于构建 Android 应用和库。
  • org.springframework.boot: 简化 Spring Boot 项目的构建。
  • org.jetbrains.kotlin.jvm, org.jetbrains.kotlin.android: 用于 Kotlin JVM 和 Android 开发。
  • org.asciidoctor.jvm.convert: 转换 Asciidoc 文档。
  • 等等。可以在 Gradle 插件门户 查找。

2.6.3 插件应用 (plugins {} / apply plugin:) 应用插件有两种主要方式:

  1. plugins {} 块 (推荐): 使用插件 ID。对于核心插件或已发布到 Gradle Plugin Portal 的插件。

    kotlin 复制代码
    plugins {
        id("java") // 核心插件
        id("org.springframework.boot") version "3.1.0" // 社区插件 (需指定版本)
        id("com.android.application") version "8.1.0" // Android 插件
    }

    这种方式简洁,且 Gradle 能高效处理。

  2. apply plugin: (旧方式): 通常在脚本底部使用。对于二进制插件(通过文件路径应用)或旧项目。

    kotlin 复制代码
    apply(plugin = "java")
    // 或者
    apply {
        plugin("java")
    }

2.6.4 插件配置 (闭包) 许多插件提供了配置块,可以在构建脚本中设置插件的行为:

kotlin 复制代码
plugins {
    id("java")
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17)) // 设置 Java 工具链版本
    }
}

// Spring Boot 插件配置
springBoot {
    mainClass.set("com.example.Application") // 设置主类
}

// Android 插件配置 (简化示例)
android {
    compileSdk = 33
    defaultConfig {
        applicationId = "com.example.myapp"
        minSdk = 24
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"
    }
}

2.7 构建生命周期 (Build Lifecycle) Gradle 构建过程分为三个清晰的阶段:

  1. 初始化阶段 (Initialization):

    • 解析 settings.gradle(.kts) 文件。
    • 确定哪些项目将参与构建(单项目或多项目)。
    • 为每个项目创建 Project 实例。
    • 执行 settings.gradle(.kts) 中的逻辑。
  2. 配置阶段 (Configuration):

    • 按需解析项目的 build.gradle(.kts) 文件(对于多项目,按依赖关系顺序)。
    • 执行构建脚本中的语句(除了任务动作 doLast/doFirst 中的代码)。
    • 注册任务、配置任务(设置 dependsOn, inputs, outputs 等)、应用插件、声明依赖等。
    • 注意: 在配置阶段执行的代码应尽量轻量,避免耗时操作(如网络请求、大量文件操作)。这些操作应放在任务动作中(执行阶段)。
  3. 执行阶段 (Execution):

    • Gradle 确定需要执行的任务(根据命令行参数和任务依赖关系图)。
    • 按顺序执行这些任务(考虑依赖关系,并行执行独立任务链)。
    • 对于每个任务,执行其 doFirstdoLast 动作块中的代码。
    • 在此阶段进行实际工作(编译、复制、运行测试等)。

理解生命周期对于编写高效、正确的构建脚本至关重要。例如,在配置阶段读取文件内容通常是个坏主意,因为它会在每次构建时发生(即使任务不需要运行)。应将这些操作移到任务动作中。


3. Gradle 脚本编写 (DSL) Gradle 提供了两种主要的 DSL:Groovy DSL 和 Kotlin DSL (KTS)。本节重点介绍 Kotlin DSL,因为它是官方推荐且日益普及的选择。

3.1 Groovy DSL vs Kotlin DSL (KTS)

  • Groovy DSL:
    • 语法灵活、简洁(动态类型、闭包、可选括号/分号)。
    • 学习曲线相对平缓(对于熟悉 Java/Groovy 的开发者)。
    • 历史更悠久,文档和社区资源丰富。
    • 动态特性可能导致运行时错误(如拼写错误)。
    • IDE 支持(自动补全、导航)不如 KTS 好。
  • Kotlin DSL (KTS):
    • 静态类型,提供更好的类型安全性和编译时检查。
    • 更优秀的 IDE 支持(在 IntelliJ IDEA 中几乎完美)。
    • 语法与 Kotlin 一致,对于 Kotlin 开发者更熟悉。
    • 构建脚本更易于重构和维护。
    • 官方推荐,代表了 Gradle 的未来方向。
    • 早期版本性能可能略逊于 Groovy,但现在差距很小。 推荐: 新项目优先选择 Kotlin DSL (KTS)。

3.2 基本语法 (变量、方法、闭包) Kotlin DSL 本质就是 Kotlin 代码,使用了 Gradle 的特定类型和扩展函数。

kotlin 复制代码
// 变量
val projectVersion = "1.0.0" // 顶层变量 (只读)
var buildCounter by extra(0) // 使用 extra 属性 (可读写)

// 方法 (函数)
fun String.toUpperCaseCustom(): String = this.toUpperCase() // 扩展函数

tasks.register("printVersion") {
    doLast {
        println("Project Version: $projectVersion")
        println("Build Counter: ${extra["buildCounter"]}") // 访问 extra
        println("Uppercase: ${"hello".toUpperCaseCustom()}")
    }
}

闭包在 Gradle DSL 中非常常见,用于配置对象(任务、依赖、扩展等)。在 KTS 中,它们对应于 lambda 表达式或 SAM 转换。

kotlin 复制代码
repositories {
    mavenCentral() // 这是一个配置闭包 (lambda) 作用于 repositories 对象
}

tasks.register<Copy>("myCopy") {
    from("src") // 配置闭包作用于 Copy 任务实例
    into("dest")
    include("*.txt")
}

3.3 项目与任务 API (project, task)

  • project: 代表当前构建脚本对应的项目。它是构建脚本的默认接收者(this)。你可以使用它来访问项目属性、配置、任务等。

    kotlin 复制代码
    println("Project name: ${project.name}")
    println("Project directory: ${project.projectDir}")
  • tasks: 是 TaskContainer 类型的对象,用于注册、查找和配置任务。

    kotlin 复制代码
    val compileTask = tasks.getByName("compileJava") // 获取任务
    tasks.named("test") { // 配置一个已存在的任务
        useJUnitPlatform()
    }

3.4 依赖管理 API (dependencies, configurations)

  • dependencies: 用于声明依赖的块。

    kotlin 复制代码
    dependencies {
        implementation("org.example:lib:1.0")
        testImplementation("junit:junit:4.13.2")
    }
  • configurations: 代表依赖配置的容器。你可以访问或修改配置。

    kotlin 复制代码
    configurations {
        // 创建一个新的配置
        create("myCustomConfiguration")
        // 配置现有的配置
        "implementation" {
            resolutionStrategy {
                failOnVersionConflict() // 版本冲突时报错
            }
        }
    }

3.5 扩展属性 (ext, extra) 用于在项目或任务上存储自定义属性。

  • 项目级 (旧 ext / 新 extra):

    kotlin 复制代码
    // 旧方式 (Groovy 风格, 在 KTS 中可用但类型不安全)
    project.ext["customProperty"] = "value"
    // 新方式 (KTS 推荐)
    extra["customProperty"] = "value"
    // 使用委托属性 (更优雅)
    val myProp by extra("initialValue")
  • 任务级:

    kotlin 复制代码
    tasks.register("myTask") {
        extra["taskSpecific"] = 42 // 任务实例上的额外属性
    }

3.6 多项目构建 (include, project) 用于构建包含多个子模块的项目。

  • settings.gradle.kts:

    kotlin 复制代码
    rootProject.name = "my-multi-project" // 设置根项目名称
    
    include(":core") // 包含子项目 'core' (位于根目录下的 'core' 文件夹)
    include(":web", ":utils") // 包含多个子项目
    includeBuild("plugins") // 包含一个组合构建 (位于 'plugins' 文件夹)
  • 子项目配置 (build.gradle.kts):

    kotlin 复制代码
    // 在子项目 'core' 的 build.gradle.kts 中
    plugins {
        `java-library` // 核心插件
    }
    
    dependencies {
        // 'core' 项目依赖
        implementation("org.apache.commons:commons-lang3:3.12.0")
    }
  • 项目间依赖:

    kotlin 复制代码
    // 在 'web' 项目的 build.gradle.kts 中
    dependencies {
        implementation(project(":core")) // 依赖 'core' 项目
    }
  • 根项目配置 (build.gradle.kts): 可以定义所有子项目的公共配置。

    kotlin 复制代码
    // 在根项目的 build.gradle.kts 中
    subprojects { // 配置所有子项目
        apply(plugin = "java")
        repositories {
            mavenCentral()
        }
        dependencies {
            testImplementation("junit:junit:4.13.2")
        }
    }
    
    allprojects { // 配置根项目和所有子项目
        group = "com.example"
        version = "1.0.0"
    }

3.7 增量构建 (up-to-date 检查) 如前所述 (2.4.5),任务通过声明 inputsoutputs 来支持增量构建。Gradle 计算这些属性的哈希值(或检查时间戳)。如果输入输出没有变化,任务就是 UP-TO-DATE 的。

3.8 构建缓存 (本地、远程) 构建缓存存储任务输出,以便在后续构建(可能在不同机器上)中重用。

  • 本地缓存: 默认启用,存储在 ~/.gradle/caches (用户主目录)。

  • 远程缓存: 需要配置(如使用 HTTP 或 S3 后端)。团队共享远程缓存可以显著加速 CI 构建和开发者之间的构建。

    kotlin 复制代码
    // 启用构建缓存 (通常默认启用)
    buildCache {
        local {
            enabled = true
        }
        remote<HttpBuildCache> {
            url = uri("https://mycache.example.com/cache/")
            credentials {
                username = "build-user"
                password = "secret"
            }
        }
    }

任务需要正确声明 outputs 才能被缓存。

3.9 编写自定义任务类型 当预定义任务类型不能满足需求时,可以创建自定义任务类型。

kotlin 复制代码
// 在 build.gradle.kts 中或 buildSrc/src/main/kotlin 中
abstract class GenerateMarkdownReport : DefaultTask() {

    @get:InputFiles // 标记为输入
    abstract val inputFiles: ConfigurableFileCollection

    @get:OutputDirectory // 标记为输出
    abstract val outputDir: DirectoryProperty

    @TaskAction // 任务执行的动作
    fun generate() {
        val outputDirFile = outputDir.get().asFile
        outputDirFile.mkdirs()
        // ... 处理 inputFiles 生成 Markdown 报告到 outputDir ...
        logger.lifecycle("Generated report in ${outputDirFile.absolutePath}")
    }
}

// 使用自定义任务类型
tasks.register<GenerateMarkdownReport>("genReport") {
    inputFiles.from(fileTree("src/docs"))
    outputDir.set(layout.buildDirectory.dir("reports/markdown"))
}

3.10 编写自定义插件 插件封装了可重用的构建逻辑、任务类型和配置。 3.10.1 插件 ID (gradlePlugin) 每个插件都有一个唯一的 ID。 3.10.2 插件实现类 (Plugin<Project>)

kotlin 复制代码
// 在 buildSrc/src/main/kotlin 或独立插件项目中
import org.gradle.api.Plugin
import org.gradle.api.Project

class MyCustomPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        // 插件被应用时的逻辑
        project.tasks.register("helloPlugin") {
            doLast {
                println("Hello from MyCustomPlugin!")
            }
        }
        // 可以添加扩展、配置项目、应用其他插件等
    }
}

3.10.3 扩展对象 (Extension) 插件可以提供配置选项给用户。

kotlin 复制代码
abstract class MyPluginExtension(project: Project) {
    abstract val message: Property<String> // 使用响应式 API
    init {
        message.convention("Default Message") // 设置默认值
    }
}

class MyCustomPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        // 创建扩展
        val extension = project.extensions.create("myPluginSettings", MyPluginExtension::class.java)

        project.tasks.register("printMessage") {
            doLast {
                println(extension.message.get()) // 使用扩展中的值
            }
        }
    }
}

在构建脚本中配置:

kotlin 复制代码
plugins {
    id("com.example.myplugin") // 假设 ID 是 com.example.myplugin
}

myPluginSettings {
    message = "Custom Message from build script"
}

3.10.4 发布到本地或仓库 为了在其他项目中使用,插件需要打包并发布。

  • 使用 java-gradle-plugin:

    kotlin 复制代码
    // 在插件项目的 build.gradle.kts 中
    plugins {
        `java-gradle-plugin`
        `maven-publish` // 用于发布
    }
    
    gradlePlugin {
        plugins {
            create("myPlugin") { // 定义插件
                id = "com.example.myplugin" // 插件 ID
                implementationClass = "com.example.MyCustomPlugin" // 实现类
            }
        }
    }
    
    publishing {
        repositories {
            maven {
                url = uri(layout.buildDirectory.dir("repo")) // 发布到本地目录
                // 或发布到远程仓库
                // url = uri("https://myrepo.com/releases")
                // credentials { ... }
            }
        }
    }

    运行 gradle publish 发布插件。


4. Gradle 最佳实践 遵循这些实践可以创建更高效、可维护和可靠的构建。

  • 4.1 优先使用 Kotlin DSL (KTS): 利用其类型安全和 IDE 优势。

  • 4.2 充分利用 Gradle Wrapper: 确保构建版本一致性。

  • 4.3 保持构建脚本简洁、可读: 避免在配置阶段做繁重工作。将复杂逻辑封装在自定义任务类型或插件中。使用注释。

  • 4.4 使用明确的依赖配置: 优先使用 implementation 而不是旧的不推荐配置 (compile)。正确使用 apiimplementation 控制传递性。

  • 4.5 管理依赖版本: 使用 libs.versions.tomlextra 属性集中管理版本号。

  • 4.6 编写可缓存的任务: 始终为任务定义清晰的 inputsoutputs。确保任务动作是纯函数(输出只由输入决定)。

  • 4.7 利用构建缓存: 在团队环境和 CI 中启用并配置远程构建缓存。

  • 4.8 使用 buildSrccomposite builds 管理插件和共享逻辑:

    • buildSrc: 一个特殊的子项目,其代码会被编译并自动添加到所有其他项目的类路径中。非常适合存放自定义任务类型、插件(仅限项目内部使用)、工具类等。位于项目根目录下的 buildSrc 文件夹。
    • composite builds: 允许你将一个独立的 Gradle 项目(通常是一个插件项目)包含到另一个构建中,就像它是该项目的一部分一样。使用 includeBuild("path/to/plugin-project")settings.gradle 中声明。
  • 4.9 编写测试: 为复杂的自定义任务类型和插件编写单元测试或集成测试(使用 Gradle TestKit)。

  • 4.10 性能调优:

    • --profile: 生成构建性能报告 (gradlew build --profile)。
    • --scan: 上传构建扫描到 scans.gradle.com 进行详细分析 (gradlew build --scan)。
    • --dry-run: 模拟任务执行而不实际运行 (gradlew build --dry-run)。
    • 减少配置时间:避免在配置阶段执行耗时操作。使用惰性 API (Provider, Property) 和任务惰性注册 (tasks.register)。
    • 优化依赖解析:使用固定的依赖版本,避免动态版本 (+)。使用 dependencyLocking
  • 4.11 安全性 (dependency verification): 启用 Gradle 的依赖验证功能,防止使用被篡改的依赖。配置信任的密钥。

    kotlin 复制代码
    // settings.gradle.kts
    dependencyVerification {
        verifyDependencies = true // 启用验证
        // 配置模式...
    }

5. Gradle 与 IDE 集成 Gradle 与主流 IDE 集成紧密。

5.1 IntelliJ IDEA / Android Studio

  • 5.1.1 导入 Gradle 项目: File > New > Project from Existing Sources... 选择项目目录下的 build.gradle.ktssettings.gradle.kts。选择 "Gradle" 作为模型。
  • 5.1.2 运行 Gradle 任务:
    • Gradle Tool Window: 在右侧边栏或 View > Tool Windows > Gradle 打开。它会列出所有项目和任务。双击任务即可运行。
    • Run Configurations: 可以创建自定义运行配置来执行特定任务或命令。
  • 5.1.3 调试构建脚本: 在任务名称或构建脚本代码行设置断点。右键点击任务或脚本,选择 Debug 'taskName'Debug 'build.gradle.kts'。调试器会在执行阶段命中断点。

5.2 Eclipse

  • 5.2.1 Buildship 插件: Eclipse 通过 Buildship 插件提供 Gradle 支持。安装此插件 (Help > Eclipse Marketplace 搜索 "Buildship")。
  • 5.2.2 导入和运行:
    • File > Import... > Gradle > Existing Gradle Project
    • 指定项目根目录。
    • Eclipse 会导入项目并创建相应的项目结构。
    • 可以在 Gradle Tasks 视图(Window > Show View > Other... > Gradle > Gradle Tasks)中查看和运行任务。

6. Gradle 高级主题 这些主题涉及 Gradle 更深层次的功能和现代 API。

  • 6.1 响应式 API (Provider, Property): Gradle 提供了 Provider<T>Property<T> 接口,用于表示值可能尚未计算出来的属性。它们支持惰性求值和值链(变换)。这是编写现代、高效插件和任务的关键。

    kotlin 复制代码
    abstract class MyTask : DefaultTask() {
        @get:Input
        abstract val inputFile: RegularFileProperty // Property<RegularFile>
    
        @get:OutputFile
        abstract val outputFile: RegularFileProperty
    
        @TaskAction
        fun run() {
            val input = inputFile.get().asFile.readText()
            val processed = process(input) // 处理输入
            outputFile.get().asFile.writeText(processed)
        }
    }
  • 6.2 惰性配置 (Lazy Configuration): 利用响应式 API 和任务惰性注册,尽可能推迟配置的计算,直到真正需要时。这可以显著减少大型项目的配置时间。

  • 6.3 配置缓存 (Configuration Cache): 这是一个实验性(但正在趋于稳定)的功能。它缓存构建脚本配置阶段的结果。对于后续构建,如果构建脚本、环境等没有变化,Gradle 可以直接从缓存中恢复配置状态,跳过整个配置阶段,直接进入执行阶段。这能带来巨大的性能提升,尤其是在配置复杂的项目中。启用:

    bash 复制代码
    gradle --configuration-cache ... # 每次运行指定

    或在 gradle.properties 中:

    properties 复制代码
    org.gradle.unsafe.configuration-cache=true # 全局启用

    注意:配置缓存对构建脚本的编写有更严格的要求(例如,限制某些外部状态访问)。

  • 6.4 自定义源集 (Source Sets): 对于非标准项目结构或需要额外源集(如集成测试),可以自定义源集。

    kotlin 复制代码
    sourceSets {
        create("integrationTest") {
            java.srcDir("src/integrationTest/java")
            resources.srcDir("src/integrationTest/resources")
            compileClasspath += sourceSets.main.get().output + configurations.testRuntimeClasspath
            runtimeClasspath += output + compileClasspath
        }
    }
    
    tasks.register<Test>("integrationTest") {
        description = "Runs integration tests."
        group = "verification"
        testClassesDirs = sourceSets["integrationTest"].output.classesDirs
        classpath = sourceSets["integrationTest"].runtimeClasspath
        shouldRunAfter("test")
    }
  • 6.5 构建变体 (Variants - Android, Native): Android Gradle Plugin (AGP) 和 Gradle 的 Native 插件利用变体维度(如 buildType - debug/release, productFlavor - free/paid, abi - x86/arm64)来构建同一个应用的不同变体。配置管理变体特定的代码、资源和依赖。

  • 6.6 构建扫描 (--scan): 如前所述,构建扫描提供了构建的深度洞察,帮助诊断性能问题、依赖问题等。上传到 scans.gradle.com

  • 6.7 持续集成集成: Gradle 与所有主流 CI 系统(Jenkins, GitLab CI, GitHub Actions, TeamCity, CircleCI 等)无缝集成。通常只需在 CI 配置中调用 ./gradlew build 或更具体的任务。利用缓存、并行化和构建扫描优化 CI 构建。

  • 6.8 发布工件到仓库: 使用 maven-publishivy-publish 插件将项目生成的构件(JAR, WAR, POM 等)发布到 Maven 或 Ivy 仓库。

    kotlin 复制代码
    plugins {
        `maven-publish`
    }
    
    publishing {
        publications {
            create<MavenPublication>("myLibrary") {
                from(components["java"]) // 发布 Java 组件 (JAR + POM)
                artifactId = "my-lib" // 可选,覆盖默认 artifactId
                versionMapping { // 处理依赖版本
                    // ...
                }
            }
        }
        repositories {
            maven {
                name = "myRepo"
                url = uri(layout.buildDirectory.dir("repo")) // 本地
                // url = uri("https://myrepo.com/releases") // 远程
                // credentials { ... }
            }
        }
    }

    运行 gradle publish 发布。


7. 完整实战案例

案例 1:构建一个简单的 Java 应用程序

7.1.1 项目结构与设置

复制代码
hello-gradle/
├── build.gradle.kts
├── settings.gradle.kts
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── example/
    │   │           └── App.java
    │   └── resources/
    └── test/
        ├── java/
        │   └── com/
        │       └── example/
        │           └── AppTest.java
        └── resources/

settings.gradle.kts:

kotlin 复制代码
rootProject.name = "hello-gradle" // 设置项目名称

build.gradle.kts:

kotlin 复制代码
plugins {
    application // 应用 application 插件 (提供 run, distZip 等任务)
}

application {
    mainClass.set("com.example.App") // 设置主类
}

repositories {
    mavenCentral() // 使用 Maven 中央仓库
}

dependencies {
    implementation("com.google.guava:guava:31.1-jre") // 示例依赖
    testImplementation("junit:junit:4.13.2") // 测试依赖
}

tasks.named<Test>("test") { // 配置测试任务
    useJUnitPlatform() // 使用 JUnit Platform (支持 JUnit 4, 5 等)
}

src/main/java/com/example/App.java:

java 复制代码
package com.example;

import com.google.common.base.Joiner;

public class App {
    public static void main(String[] args) {
        String message = Joiner.on(", ").join("Hello", "Gradle", "World!");
        System.out.println(message);
    }
}

src/test/java/com/example/AppTest.java:

java 复制代码
package com.example;

import org.junit.Test;
import static org.junit.Assert.*;

public class AppTest {
    @Test
    public void testAppHasMessage() {
        App app = new App();
        assertNotNull(app); // 简单示例测试
    }
}

7.1.6 运行任务

  • 运行应用程序: ./gradlew run (会输出 Hello, Gradle, World!)
  • 运行测试: ./gradlew test (报告测试通过)
  • 构建 JAR: ./gradlew jar (JAR 文件在 build/libs/hello-gradle.jar)
  • 构建分发 ZIP: ./gradlew distZip (包含 JAR 和启动脚本的 ZIP 在 build/distributions/)

案例 2:构建一个多模块项目 (Java Library + Web Application)

7.2.1 项目结构 (settings.gradle.kts)

复制代码
multi-module/
├── build.gradle.kts
├── settings.gradle.kts
├── core/ (Java Library)
│   ├── build.gradle.kts
│   └── src/...
├── web/ (Web Application)
│   ├── build.gradle.kts
│   └── src/...
└── buildSrc/ (共享逻辑 - 可选)
    └── src/main/kotlin/...

settings.gradle.kts:

kotlin 复制代码
rootProject.name = "multi-module-project"

include(":core", ":web") // 包含 core 和 web 子项目

build.gradle.kts (根项目):

kotlin 复制代码
// 配置所有子项目的公共设置
subprojects {
    apply(plugin = "java") // 所有子项目都是 Java 项目
    repositories {
        mavenCentral()
    }
    dependencies {
        testImplementation("junit:junit:4.13.2")
    }
    // 设置 Java 版本
    java {
        toolchain {
            languageVersion.set(JavaLanguageVersion.of(17))
        }
    }
}

// 也可以配置特定项目
project(":web") {
    apply(plugin = "war") // 只为 web 项目应用 war 插件
}

core/build.gradle.kts:

kotlin 复制代码
plugins {
    `java-library` // 更适合库项目的插件
}

dependencies {
    // core 项目依赖
    implementation("org.apache.commons:commons-lang3:3.12.0")
}
// ... core 项目其他配置 ...

web/build.gradle.kts:

kotlin 复制代码
plugins {
    war // 应用 war 插件 (已由根项目应用)
}

dependencies {
    implementation(project(":core")) // 依赖 core 模块
    implementation("javax.servlet:javax.servlet-api:4.0.1") // Servlet API
    // ... web 项目其他依赖 ...
}

// ... web 项目其他配置 (如设置 contextPath) ...

7.2.5 定义根项目任务 根项目的 build 任务会依赖所有子项目的 build 任务。clean 同理。 运行 ./gradlew build 会构建所有子项目。运行 ./gradlew :core:build 只构建 core 模块。

案例 3:编写一个自定义 Gradle 插件 (Kotlin)

我们将创建一个插件,它添加一个任务来生成一个包含项目版本信息的文本文件。

7.3.1 创建插件项目 项目结构:

复制代码
version-plugin/ (独立插件项目)
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    └── main/
        └── kotlin/
            └── com/
                └── example/
                    └── versionplugin/
                        ├── VersionExtension.kt
                        ├── GenerateVersionFilePlugin.kt
                        └── GenerateVersionFileTask.kt

settings.gradle.kts:

kotlin 复制代码
rootProject.name = "version-plugin"

build.gradle.kts:

kotlin 复制代码
plugins {
    `java-gradle-plugin` // 用于开发 Gradle 插件
    `maven-publish`      // 用于发布插件
    `kotlin-dsl`         // 使用 Kotlin DSL 编写插件
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(gradleApi()) // 引入 Gradle API
    testImplementation("junit:junit:4.13.2")
}

gradlePlugin {
    plugins {
        create("versionPlugin") { // 定义插件
            id = "com.example.versionplugin" // 插件 ID
            implementationClass = "com.example.versionplugin.GenerateVersionFilePlugin" // 实现类
        }
    }
}

publishing {
    repositories {
        maven {
            url = uri(layout.buildDirectory.dir("repo")) // 发布到本地目录
        }
    }
}

src/main/kotlin/com/example/versionplugin/VersionExtension.kt:

kotlin 复制代码
package com.example.versionplugin

import org.gradle.api.provider.Property

abstract class VersionExtension {
    abstract val outputDir: Property<String> // 输出目录 (相对于项目目录)
    init {
        outputDir.convention("build/version-info") // 默认值
    }
}

src/main/kotlin/com/example/versionplugin/GenerateVersionFileTask.kt:

kotlin 复制代码
package com.example.versionplugin

import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import java.io.File

abstract class GenerateVersionFileTask : DefaultTask() {

    @get:Input
    abstract val projectVersion: Property<String> // 项目版本 (来自 Project)

    @get:OutputDirectory
    abstract val outputDir: DirectoryProperty // 输出目录

    @TaskAction
    fun generate() {
        val outputDirFile = outputDir.get().asFile
        outputDirFile.mkdirs()
        val versionFile = File(outputDirFile, "version.txt")
        versionFile.writeText("Project Version: ${projectVersion.get()}\n")
        logger.lifecycle("Generated version file at: ${versionFile.absolutePath}")
    }
}

src/main/kotlin/com/example/versionplugin/GenerateVersionFilePlugin.kt:

kotlin 复制代码
package com.example.versionplugin

import org.gradle.api.Plugin
import org.gradle.api.Project

class GenerateVersionFilePlugin : Plugin<Project> {
    override fun apply(project: Project) {
        // 1. 创建扩展对象
        val extension = project.extensions.create("versionInfo", VersionExtension::class.java)

        // 2. 注册自定义任务
        project.tasks.register("generateVersionFile", GenerateVersionFileTask::class.java) {
            group = "Versioning"
            description = "Generates a file with the project version information"
            projectVersion.set(project.provider { project.version.toString() }) // 使用 Project 的 version
            outputDir.set(project.layout.projectDirectory.dir(extension.outputDir)) // 使用扩展中的配置
        }
    }
}

7.3.7 发布到本地 Maven 仓库 在插件项目根目录运行:

bash 复制代码
./gradlew publish

插件将被发布到 build/repo 目录。

7.3.8 在另一个项目中应用自定义插件 创建一个新的消费者项目。 consumer-project/build.gradle.kts:

kotlin 复制代码
plugins {
    id("com.example.versionplugin") version "1.0.0" // 应用插件 (假设版本是 1.0.0)
}

// 配置插件扩展
versionInfo {
    outputDir = "custom-output" // 覆盖默认输出目录
}

// 依赖本地 Maven 仓库 (包含插件)
repositories {
    maven {
        url = uri("/path/to/version-plugin/build/repo") // 指向插件发布目录
    }
}

consumer-project/settings.gradle.kts:

kotlin 复制代码
rootProject.name = "consumer-project"

7.3.9 运行任务 在消费者项目中运行:

bash 复制代码
./gradlew generateVersionFile

任务将运行,并在 custom-output/version.txt 文件中写入项目版本信息。


8. 总结与资源

  • 8.1 Gradle 官方文档: https://docs.gradle.org/ (最权威、最全面的资源)
  • 8.2 Gradle 社区论坛: https://discuss.gradle.org/ (提问和交流)
  • 8.3 书籍推荐:
    • Gradle in Action (Manning)
    • Building and Testing with Gradle (O'Reilly)
  • 8.4 持续学习: Gradle 是一个活跃发展的项目。关注官方博客、Release Notes 和社区动态,学习新特性和最佳实践。

这份指南涵盖了 Gradle 的核心概念、使用方法和高级主题,并提供了可直接运行的实战案例。希望它能帮助你掌握 Gradle,构建更高效、可靠的软件项目!

相关推荐
青云计划12 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿12 小时前
Jsoniter(java版本)使用介绍
java·开发语言
探路者继续奋斗13 小时前
IDD意图驱动开发之意图规格说明书
java·规格说明书·开发规范·意图驱动开发·idd
消失的旧时光-194314 小时前
第十九课:为什么要引入消息队列?——异步系统设计思想
java·开发语言
A懿轩A14 小时前
【Java 基础编程】Java 面向对象入门:类与对象、构造器、this 关键字,小白也能写 OOP
java·开发语言
乐观勇敢坚强的老彭15 小时前
c++寒假营day03
java·开发语言·c++
biubiubiu070615 小时前
谷歌浏览器无法访问localhost:8080
java
大黄说说15 小时前
新手选语言不再纠结:Java、Python、Go、JavaScript 四大热门语言全景对比与学习路线建议
java·python·golang
烟沙九洲15 小时前
Java 中的 封装、继承、多态
java
识君啊15 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端