欢迎光临
我们一直在努力

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

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


目录

  • Gradle 是什么?为什么选择 Gradle?
    • 1.1 构建工具的概念
    • 1.2 Gradle 的核心优势
    • 1.3 Gradle vs Maven vs Ant
  • 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>)
  • 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 发布到本地或仓库
  • Gradle 最佳实践
    • 4.1 优先使用 Kotlin DSL (KTS)
    • 4.2 充分利用 Gradle Wrapper
    • 4.3 保持构建脚本简洁、可读
    • 4.4 使用明确的依赖配置
    • 4.5 管理依赖版本 (使用 versions.toml 或 extra 属性)
    • 4.6 编写可缓存的任务 (定义 inputs/outputs)
    • 4.7 利用构建缓存
    • 4.8 使用 buildSrc 或 composite builds 管理插件和共享逻辑
    • 4.9 编写测试
    • 4.10 性能调优 (–profile, –scan, –dry-run)
    • 4.11 安全性 (dependency verification)
  • 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 导入和运行
  • 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)
  • 完整实战案例
    • 案例 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.properties 或 buildSrc)
      • 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.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。

    # 安装 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 手动安装

  • 访问 Gradle 官网下载页面。
  • 下载你需要的版本(通常是完整的二进制分发版,如 gradle-8.5-bin.zip)。
  • 解压下载的文件到你选择的目录(例如 /opt/gradle 或 C:\\Gradle)。
  • 2.1.3 环境变量配置 (GRADLE_HOME, PATH)

    • Linux/macOS: # 编辑 ~/.bashrc 或 ~/.zshrc
      export GRADLE_HOME=/path/to/gradle # 例如 /opt/gradle/gradle-8.5
      export PATH=$PATH:$GRADLE_HOME/bin

      # 使配置生效
      source ~/.bashrc # 或 source ~/.zshrc

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

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

    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) 文件: 这是构建过程的入口点。它定义了哪些项目参与此次构建(对于单项目构建,它通常只定义根项目名称;对于多项目构建,它使用 include 或 includeBuild 来包含子项目或组合构建)。
    • 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 脚本 (./gradlew 或 gradlew.bat),Wrapper 会自动下载并安装指定版本的 Gradle(如果尚未安装)。

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

    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 终端中: ./gradlew clean build
    • 在 Windows 命令提示符或 PowerShell 中: 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: 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): // 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 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 中的动作会在任务执行阶段最先执行。一个任务可以有多个 doFirst 和 doLast 动作,它们按添加顺序执行。

    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) 之前运行,因为测试需要编译好的类文件。

    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 根据输出文件的时间戳和内容来检查任务是否需要重新运行。

    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 需要知道从哪里下载这些库。

    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 {} 块中声明项目所需的依赖。

    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): 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): 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)。
    • 在 gradle 目录下创建 libs.versions.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" }

    • 在 build.gradle.kts 中使用: dependencies {
      implementation(libs.spring.boot.starter.web) // 类型安全访问器
      implementation(libs.guava)
      }
    • 版本目录提供了更好的集中管理、类型安全和 IDE 支持。

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

    • 查看依赖树: gradle dependencies 或 gradle :module:dependencies。
    • 强制指定版本: configurations.all {
      resolutionStrategy {
      force("com.google.guava:guava:31.1-jre") // 强制使用此版本
      }
      }
    • 排除特定依赖: 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 插件更适合构建供其他项目使用的库(区分 api 和 implementation)。

    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:) 应用插件有两种主要方式:

  • plugins {} 块 (推荐): 使用插件 ID。对于核心插件或已发布到 Gradle Plugin Portal 的插件。 plugins {
    id("java") // 核心插件
    id("org.springframework.boot") version "3.1.0" // 社区插件 (需指定版本)
    id("com.android.application") version "8.1.0" // Android 插件
    }
    这种方式简洁,且 Gradle 能高效处理。
  • apply plugin: (旧方式): 通常在脚本底部使用。对于二进制插件(通过文件路径应用)或旧项目。 apply(plugin = "java")
    // 或者
    apply {
    plugin("java")
    }
  • 2.6.4 插件配置 (闭包) 许多插件提供了配置块,可以在构建脚本中设置插件的行为:

    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 构建过程分为三个清晰的阶段:

  • 初始化阶段 (Initialization):

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

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

    • Gradle 确定需要执行的任务(根据命令行参数和任务依赖关系图)。
    • 按顺序执行这些任务(考虑依赖关系,并行执行独立任务链)。
    • 对于每个任务,执行其 doFirst 和 doLast 动作块中的代码。
    • 在此阶段进行实际工作(编译、复制、运行测试等)。
  • 理解生命周期对于编写高效、正确的构建脚本至关重要。例如,在配置阶段读取文件内容通常是个坏主意,因为它会在每次构建时发生(即使任务不需要运行)。应将这些操作移到任务动作中。


    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 的特定类型和扩展函数。

    // 变量
    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 转换。

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

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

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

    • project: 代表当前构建脚本对应的项目。它是构建脚本的默认接收者(this)。你可以使用它来访问项目属性、配置、任务等。 println("Project name: ${project.name}")
      println("Project directory: ${project.projectDir}")
    • tasks: 是 TaskContainer 类型的对象,用于注册、查找和配置任务。 val compileTask = tasks.getByName("compileJava") // 获取任务
      tasks.named("test") { // 配置一个已存在的任务
      useJUnitPlatform()
      }

    3.4 依赖管理 API (dependencies, configurations)

    • dependencies: 用于声明依赖的块。 dependencies {
      implementation("org.example:lib:1.0")
      testImplementation("junit:junit:4.13.2")
      }
    • configurations: 代表依赖配置的容器。你可以访问或修改配置。 configurations {
      // 创建一个新的配置
      create("myCustomConfiguration")
      // 配置现有的配置
      "implementation" {
      resolutionStrategy {
      failOnVersionConflict() // 版本冲突时报错
      }
      }
      }

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

    • 项目级 (旧 ext / 新 extra): // 旧方式 (Groovy 风格, 在 KTS 中可用但类型不安全)
      project.ext["customProperty"] = "value"
      // 新方式 (KTS 推荐)
      extra["customProperty"] = "value"
      // 使用委托属性 (更优雅)
      val myProp by extra("initialValue")
    • 任务级: tasks.register("myTask") {
      extra["taskSpecific"] = 42 // 任务实例上的额外属性
      }

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

    • settings.gradle.kts: rootProject.name = "my-multi-project" // 设置根项目名称

      include(":core") // 包含子项目 'core' (位于根目录下的 'core' 文件夹)
      include(":web", ":utils") // 包含多个子项目
      includeBuild("plugins") // 包含一个组合构建 (位于 'plugins' 文件夹)

    • 子项目配置 (build.gradle.kts): // 在子项目 'core' 的 build.gradle.kts 中
      plugins {
      `java-library` // 核心插件
      }

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

    • 项目间依赖: // 在 'web' 项目的 build.gradle.kts 中
      dependencies {
      implementation(project(":core")) // 依赖 'core' 项目
      }
    • 根项目配置 (build.gradle.kts): 可以定义所有子项目的公共配置。 // 在根项目的 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),任务通过声明 inputs 和 outputs 来支持增量构建。Gradle 计算这些属性的哈希值(或检查时间戳)。如果输入输出没有变化,任务就是 UP-TO-DATE 的。

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

    • 本地缓存: 默认启用,存储在 ~/.gradle/caches (用户主目录)。
    • 远程缓存: 需要配置(如使用 HTTP 或 S3 后端)。团队共享远程缓存可以显著加速 CI 构建和开发者之间的构建。 // 启用构建缓存 (通常默认启用)
      buildCache {
      local {
      enabled = true
      }
      remote<HttpBuildCache> {
      url = uri("https://mycache.example.com/cache/")
      credentials {
      username = "build-user"
      password = "secret"
      }
      }
      }

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

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

    // 在 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>)

    // 在 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) 插件可以提供配置选项给用户。

    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()) // 使用扩展中的值
    }
    }
    }
    }

    在构建脚本中配置:

    plugins {
    id("com.example.myplugin") // 假设 ID 是 com.example.myplugin
    }

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

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

    • 使用 java-gradle-plugin: // 在插件项目的 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)。正确使用 api 和 implementation 控制传递性。
    • 4.5 管理依赖版本: 使用 libs.versions.toml 或 extra 属性集中管理版本号。
    • 4.6 编写可缓存的任务: 始终为任务定义清晰的 inputs 和 outputs。确保任务动作是纯函数(输出只由输入决定)。
    • 4.7 利用构建缓存: 在团队环境和 CI 中启用并配置远程构建缓存。
    • 4.8 使用 buildSrc 或 composite 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 的依赖验证功能,防止使用被篡改的依赖。配置信任的密钥。 // 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.kts 或 settings.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> 接口,用于表示值可能尚未计算出来的属性。它们支持惰性求值和值链(变换)。这是编写现代、高效插件和任务的关键。 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 可以直接从缓存中恢复配置状态,跳过整个配置阶段,直接进入执行阶段。这能带来巨大的性能提升,尤其是在配置复杂的项目中。启用: gradle –configuration-cache … # 每次运行指定
      或在 gradle.properties 中: org.gradle.unsafe.configuration-cache=true # 全局启用
      注意:配置缓存对构建脚本的编写有更严格的要求(例如,限制某些外部状态访问)。
    • 6.4 自定义源集 (Source Sets): 对于非标准项目结构或需要额外源集(如集成测试),可以自定义源集。 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-publish 或 ivy-publish 插件将项目生成的构件(JAR, WAR, POM 等)发布到 Maven 或 Ivy 仓库。 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:

    rootProject.name = "hello-gradle" // 设置项目名称

    build.gradle.kts:

    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:

    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:

    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:

    rootProject.name = "multi-module-project"

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

    build.gradle.kts (根项目):

    // 配置所有子项目的公共设置
    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:

    plugins {
    `java-library` // 更适合库项目的插件
    }

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

    web/build.gradle.kts:

    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:

    rootProject.name = "version-plugin"

    build.gradle.kts:

    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:

    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:

    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:

    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 仓库 在插件项目根目录运行:

    ./gradlew publish

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

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

    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:

    rootProject.name = "consumer-project"

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

    ./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,构建更高效、可靠的软件项目!

    赞(0)
    未经允许不得转载:171主机测评 » Gradle全面指南:从入门到精通
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址