Article

项目构建 Gradle

更新于:2026-07-14

第一章:Gradle 入门与基础概念

1.1 什么是 Gradle

概念名称说明注意事项
Gradle一个基于 Groovy 或 Kotlin DSL 的自动化构建工具,用于编译、测试、打包和部署项目。它结合了 Ant 的灵活性和 Maven 的约定优于配置理念。Gradle 不是仅限于 Java 的工具,广泛用于 Android、Groovy、Scala、Kotlin 等项目构建。
构建自动化指通过脚本自动完成编译、依赖管理、测试、打包、部署等重复性任务的过程。手动构建易出错且效率低,Gradle 提供声明式和可扩展的方式来实现自动化。
DSL(领域特定语言)Gradle 使用 Groovy 或 Kotlin 编写的 DSL 来定义构建逻辑,比 XML 更简洁、更具表达力。不同于通用编程语言,DSL 专为构建任务设计,学习成本较低但需熟悉语法结构。
构建脚本(build.gradle)Gradle 的核心配置文件,使用 DSL 编写,定义项目行为、任务、依赖等。默认使用 Groovy 语法(.gradle),也支持 Kotlin(.kts),初学者建议从 Groovy 入门。

1.2 Gradle 与 Maven、Ant 的对比

对比维度GradleMavenAnt
配置方式基于 Groovy/Kotlin DSL(代码式)基于 XML(声明式)基于 XML(过程式)
灵活性高,可通过代码完全控制构建逻辑中等,插件机制较固定高,但需手动编写所有逻辑
学习曲线中等,需了解 DSL 和编程概念低,结构固定易于上手高,需掌握 XML 和构建流程
构建性能高,支持增量构建、缓存、并行执行一般,全量构建较多低,无内置优化机制
依赖管理强大,支持动态版本、传递依赖、冲突解决强大,基于中央仓库机制弱,需手动管理
插件机制灵活,可编写自定义插件并动态应用丰富,生态成熟但扩展受限需手动集成,不够模块化
默认约定支持”约定优于配置”,也可自定义强调”约定优于配置”无默认结构,完全自定义
脚本可读性高,DSL 接近自然语言低,XML 冗长且嵌套深低,逻辑分散不易维护
多项目构建支持优秀,原生支持复杂项目结构支持,但配置繁琐支持,需大量脚本编写
使用场景Android 开发、复杂项目、CI/CD 流水线Java 企业项目、标准 Maven 项目遗留系统、高度定制化构建

注意事项:

  • Maven 适合标准化项目,Gradle 更适合需要灵活性和高性能的现代项目。
  • Ant 已逐渐被取代,但在某些遗留系统中仍有使用。
  • Gradle 兼容 Maven 仓库,可无缝使用现有依赖。

1.3 Gradle 的核心特性(DSL、增量构建、依赖管理等)

特性名称说明注意事项
基于 DSL 的构建脚本使用 Groovy 或 Kotlin 编写构建逻辑,语法简洁,支持编程结构(条件、循环、函数等)。初学者需理解闭包和委托机制,避免过度复杂化脚本。
增量构建(Incremental Build)Gradle 能识别任务输入输出变化,仅重新执行受影响的任务,大幅提升构建速度。必须正确标注任务的 @Input 和 @Output,否则无法判断是否可跳过。
任务依赖管理支持显式定义任务依赖(dependsOn),自动调度执行顺序。避免循环依赖,否则构建失败。
强大的依赖管理支持本地/远程仓库(Maven、Ivy)、动态版本、排除传递依赖、依赖配置(configurations)。动态版本(如 1.+)可能导致构建不一致,生产环境建议锁定版本。
多项目构建支持将大型项目拆分为多个子项目,统一管理依赖和配置。需在 settings.gradle 中声明子项目,并合理设计项目间依赖。
插件系统提供标准化方式扩展功能(如 Java 插件、Android 插件),支持自定义插件开发。官方插件稳定,第三方插件需评估兼容性和维护状态。
构建缓存支持本地和远程缓存,复用任务输出,减少重复构建。需启用缓存功能(—build-cache),并确保任务幂等性。
并行构建可并行执行独立任务,充分利用多核 CPU 提升性能。在 gradle.properties 中设置 org.gradle.parallel=true。
生命周期监听提供初始化、配置、执行阶段的钩子,便于监控和干预构建过程。钩子代码应轻量,避免阻塞主线程。
Wrapper 支持提供 gradlew 脚本,确保团队使用统一 Gradle 版本,无需手动安装。推荐项目中包含 wrapper 文件,便于 CI/CD 集成。

1.4 Gradle 的安装与环境配置

方法名称语法用途代码示例注意事项
手动安装(官网下载)1. 下载 Gradle 发行包
2. 解压到目录
3. 配置环境变量
手动控制版本,适合学习和测试下载地址:https://gradle.org/releases/需手动维护版本升级
环境变量配置(GRADLE_HOME)GRADLE_HOME = /path/to/gradle指定 Gradle 安装根目录export GRADLE_HOME=/opt/gradle-8.5Windows 使用系统属性设置
PATH 添加PATH = $PATH:$GRADLE_HOME/bin使 gradle 命令全局可用export PATH=$PATH:$GRADLE_HOME/bin配置后需重启终端或 source ~/.bashrc
验证安装gradle -v查看 Gradle 版本及环境信息gradle -v应显示 Gradle 版本、Groovy、JVM 信息
使用 SDKMAN!(Linux/macOS)sdk install gradle 8.5通过 SDK 管理工具安装sdk install gradle 8.5推荐开发者使用,方便版本切换
使用 Chocolatey(Windows)choco install gradleWindows 包管理器安装choco install gradle需管理员权限运行 CMD
Gradle Wrapper(推荐)gradle wrapper生成 wrapper 文件,避免手动安装gradle wrapper --gradle-version 8.5项目级版本控制,CI/CD 友好

注意事项:

  • 安装前需确保已安装 JDK 8 或更高版本。
  • 推荐使用 Gradle Wrapper(gradlew),避免团队版本不一致问题。
  • 验证安装时若提示”command not found”,检查 PATH 是否正确配置。

1.5 Gradle 命令行基础使用

命令名称语法用途代码示例注意事项
gradle tasksgradle tasks [--all]列出项目中所有可执行任务gradle tasks
gradle tasks --all
--all 显示所有任务(含隐藏任务)
gradle buildgradle build执行完整构建(编译、测试、打包等)gradle build是最常用的构建命令
gradle cleangradle clean删除 build 目录,清理输出文件gradle clean清理后重新构建可避免缓存问题
gradle helpgradle help --task <任务名>查看任务帮助信息gradle help --task build可查看任务用途和依赖
gradle -qgradle -q build静默模式执行任务(减少日志输出)gradle -q build-q 表示 quiet 模式
gradle -igradle -i build输出信息级日志(info)gradle -i build用于调试构建过程
gradle -dgradle -d build输出调试级日志(debug)gradle -d build日志最多,用于深入排查问题
gradle —dry-rungradle --dry-run build模拟执行,不真正运行任务gradle --dry-run build查看任务执行顺序,不实际执行
gradle —continuegradle --continue build即使某任务失败也继续执行其他任务gradle --continue build用于多任务场景,收集全部错误
gradle wrappergradle wrapper --gradle-version X.X生成 Gradle Wrapper 文件gradle wrapper --gradle-version 8.5生成 gradlew, gradlew.bat, wrapper JAR
./gradlew./gradlew build使用 Wrapper 执行构建./gradlew build推荐在项目中始终使用此方式

注意事项:

  • 所有命令应在包含 build.gradle 的目录中执行。
  • gradlew 自动下载指定版本的 Gradle,无需本地安装。
  • 日志级别:-q(quiet)< 默认 < -i(info)< -d(debug)
  • 使用 --info-i 可查看任务是否被 UP-TO-DATE 跳过。

第二章:Gradle 构建脚本基础(build.gradle)

2.1 build.gradle 文件结构概述

概念名称说明注意事项
脚本顶层块(Top-level blocks)build.gradle 文件由多个 DSL 块组成,用于配置项目不同方面。每个块有特定作用域,不能随意嵌套。
plugins {}用于应用 Gradle 插件,通常位于文件顶部。使用此方式应用的是二进制插件,需指定插件 ID。
apply plugin: ‘java’老式插件应用语法,通过 apply 方法引入插件。适用于脚本插件或未在插件门户注册的插件。
group / version / description项目元数据属性,定义项目组、版本和描述信息。通常用于多项目构建或发布场景。
repositories {}配置依赖仓库(如 Maven Central、JCenter、自定义仓库)。必须配置才能下载外部依赖。
dependencies {}声明项目依赖,按配置(configuration)分类管理。不同配置对应不同使用场景(编译、运行时等)。
sourceSets {}定义源码目录结构(如 Java 源码、资源文件路径)。可自定义目录,覆盖默认约定。
task 定义块使用 task 关键字定义自定义任务。可带动作(action)或配置属性。
ext {} 或 ext.属性 = 值定义扩展属性,用于在项目中共享变量。类似全局变量,便于统一管理配置。
configurations {}自定义依赖配置(较少使用,通常用默认配置)。高级用法,用于特殊依赖管理需求。

注意事项:

  • plugins {} 块必须位于文件最前(除注释外),不可包含逻辑代码。
  • 多个 build.gradle 文件可存在于多项目构建中,每个子项目可独立配置。
  • Groovy DSL 中分号可省略,每行一条语句即可。

2.2 项目与任务(Project 与 Task)

概念名称说明注意事项
ProjectGradle 构建中的基本单元,每个 build.gradle 对应一个 Project 实例。通过 project 对象可访问项目属性和方法。
Task构建中的最小执行单元,如编译、打包、测试等。每个任务是 org.gradle.api.Task 的实例。
内建任务插件自动创建的任务(如 Java 插件的 compileJava、test)。无需手动定义,应用插件后自动可用。
自定义任务用户通过 task 关键字或类定义的任务。可实现特定构建逻辑。
任务动作(Action)任务执行的具体操作,通过 doLast 或 doFirst 添加。doLast 添加到任务末尾,doFirst 添加到开头。
任务状态任务执行后有不同状态:SUCCESS、FAILED、SKIPPED、UP-TO-DATE。UP-TO-DATE 表示输入未变,跳过执行。
项目层次结构单项目或多层次项目(root project + subprojects)。settings.gradle 控制项目包含关系。
project 对象在 build.gradle 中隐式可用,代表当前项目。可调用 project.property 访问属性。
task 对象每个任务是 Task 接口的实现,可配置属性和行为。支持动态添加属性和方法。
生命周期方法project 提供 afterEvaluate、beforeEvaluate 等钩子。用于在配置阶段后干预项目配置。

注意事项:

  • 所有配置代码在配置阶段执行,任务动作在执行阶段执行。
  • 避免在任务动作中进行复杂配置,应放在配置块中。
  • 可通过 tasks 集合访问所有任务(如 tasks.build)。

2.3 任务定义与执行(task)

方法名称语法用途代码示例注意事项
task(关键字)task <任务名>定义一个空任务task hello最基础的任务定义方式
task with typetask <任务名>(type: <任务类型>)创建指定类型的任务task zip(type: Zip)用于创建内建任务类型实例
task with actiontask <任务名> { doLast { ... } }定义任务并添加执行动作task hello { doLast { println 'Hello' } }doLast 添加动作到任务末尾
task with doFirsttask <任务名> { doFirst { ... } }添加动作到任务开始前task hello { doFirst { println 'Start' } }多个 doFirst 按逆序执行
task with descriptiontask <任务名> { description = '...' }设置任务描述task hello { description = 'Prints hello' }可通过 tasks 查看
task with grouptask <任务名> { group = '...' }设置任务所属分组task hello { group = 'custom' }组织任务显示结构
task with propertytask <任务名> { <属性> = <值> }配置任务属性task copyFiles(type: Copy) { from 'src'; into 'dest' }不同任务类型支持不同属性
task (lazy)tasks.register('name') { ... }惰性注册任务(推荐方式)tasks.register('hello') { doLast { println 'Hello' } }仅在需要时创建,提升性能
task (eager)tasks.create('name') { ... }立即创建任务tasks.create('hello') { doLast { println 'Hello' } }立即执行配置,兼容旧写法
调用任务gradle <任务名>从命令行执行任务gradle hello在项目根目录执行

注意事项:

  • 使用 tasks.register 是现代 Gradle 推荐方式,支持惰性求值。
  • doLast 和 doFirst 可多次调用,动作按顺序执行。
  • 任务名不能包含空格,建议使用驼峰命名法(如 myTask)。
  • 任务定义后可通过 gradle tasks 查看是否注册成功。

2.4 任务依赖(dependsOn)

方法名称语法用途代码示例注意事项
dependsOn(属性)taskA.dependsOn taskB设置任务 A 依赖任务 Btask taskB { doLast { println 'B' } }
task taskA(dependsOn: taskB) { doLast { println 'A' } }
taskA 执行前先执行 taskB
dependsOn(方法)taskA.dependsOn(taskB)动态设置依赖关系taskA.dependsOn(taskB)可在配置阶段任意位置调用
dependsOn(多个任务)taskA.dependsOn taskB, taskC依赖多个任务taskA.dependsOn(taskB, taskC)所有依赖任务执行完后才执行 taskA
dependsOn(任务集合)taskA.dependsOn tasks.matching { ... }依赖符合条件的任务taskA.dependsOn(tasks.matching { it.name.startsWith('compile') })动态依赖,适用于多源集场景
dependsOn(字符串)taskA.dependsOn 'taskB'通过任务名设置依赖taskA.dependsOn('taskB')适用于跨项目或后定义任务
dependsOn(闭包)taskA.dependsOn { [...] }惰性计算依赖列表taskA.dependsOn { project.hasProperty('runTests') ? [test] : [] }依赖列表在执行前计算
mustRunAftertaskA.mustRunAfter taskB指定顺序但不强制依赖taskA.mustRunAfter(taskB)不影响执行计划,仅排序
finalizedBytaskA.finalizedBy taskB无论 taskA 成功或失败,都执行 taskBtaskA.finalizedBy(taskB)常用于清理或报告任务

注意事项:

  • dependsOn 创建强依赖,确保依赖任务完成后再执行当前任务。
  • 避免循环依赖(A→B→A),会导致构建失败。
  • mustRunAfter 不是依赖,仅控制执行顺序,若 taskB 不执行,taskA 仍可运行。
  • finalizedBy 用于确保清理任务始终执行(如 stopTomcat.finalizedBy cleanUp)。

2.5 任务分组与描述(group, description)

方法名称语法用途代码示例注意事项
group(属性)taskX.group = 'GroupName'设置任务所属分组task hello { group = 'custom' }分组用于组织任务显示
group(构造参数)task (group: 'GroupName')定义任务时指定分组task hello(group: 'utility') { doLast { ... } }与 description 一起使用更清晰
description(属性)taskX.description = '...'设置任务描述信息task hello { description = 'Prints greeting' }通过 gradle tasks 查看
description(构造参数)task (description: '...')定义任务时指定描述task hello(description: 'Say hello') { doLast { ... } }推荐为自定义任务添加描述
查看任务信息gradle tasks --all显示所有任务及其分组和描述gradle tasks --all--all 显示隐藏任务
内建分组名称'build', 'documentation', 'verification', 'publishing', 'custom'Gradle 推荐的标准分组task generateReport { group = 'documentation' }遵循惯例便于理解
自定义分组任意字符串创建自定义任务类别task deploy(group: 'deployment', description: 'Deploy app')建议命名清晰一致

注意事项:

  • 为自定义任务设置 group 和 description 是最佳实践,便于团队协作。
  • 分组名建议使用小写字母,单词间用连字符或空格分隔。
  • 未设置分组的任务默认归为”Other tasks”。
  • 描述应简洁明了,说明任务用途。

第三章:Gradle 生命周期与执行流程

3.1 初始化阶段(Initialization)

概念名称说明注意事项
初始化阶段Gradle 构建的第一个阶段,确定构建哪些项目(Project)并创建项目实例。该阶段仅运行一次,决定整个构建的项目范围。
settings.gradle位于项目根目录,用于配置多项目构建结构。必须存在才能正确初始化多项目。
include在 settings.gradle 中使用,声明包含的子项目。语法:include 'sub1', 'sub2'include ':sub1'
project.name设置项目名称,可覆盖目录名。在 settings.gradle 中配置:findProject(':sub1')?.name = 'module1'
Gradle 版本选择通过 Gradle Wrapper(gradle/wrapper/gradle-wrapper.properties)确定使用哪个 Gradle 版本。推荐使用 Wrapper 保证环境一致性。
多项目结构识别Gradle 解析 settings.gradle 并构建项目树结构。根项目和子项目均在初始化阶段创建。
单项目构建若无 settings.gradle,Gradle 将当前目录视为单项目。适用于简单项目。
异常处理若 settings.gradle 语法错误或项目路径不存在,初始化失败。构建终止,输出错误信息。
初始化脚本(init scripts)使用 -I 参数指定,用于全局配置(如企业级仓库设置)。高级用法,影响所有构建。
buildSrc 项目特殊子项目,用于存放构建脚本的源码,在初始化后自动编译。代码位于根目录的 buildSrc/ 下。

注意事项:

  • settings.gradle 必须在根项目目录下。
  • 初始化阶段不执行任何任务,仅确定项目结构。
  • 可通过 --include-build 将外部构建包含进来(复合构建)。

3.2 配置阶段(Configuration)

概念名称说明注意事项
配置阶段第二阶段,执行所有项目的 build.gradle 脚本,配置 Project 和 Task 对象。所有任务都会被配置,无论是否执行。
脚本执行每个 build.gradle 文件在此阶段被解析并执行。包括变量定义、插件应用、任务创建等。
插件应用plugins {} 或 apply plugin: 在此阶段生效,添加任务和配置。插件会扩展 Project 对象。
任务创建所有 task 定义在此阶段注册到 Project 中。即使任务不执行也会被创建。
依赖解析(配置时)dependencies {} 块被读取,但依赖尚未下载。实际下载发生在执行阶段需要时。
属性计算所有 ext 扩展属性、项目属性在此阶段确定。可用于后续任务配置。
任务配置任务的 group、description、inputs/outputs 等属性被设置。动作(doFirst/doLast)被添加但不执行。
afterEvaluateproject.afterEvaluate { } 钩子在此阶段末尾执行。用于配置已被其他插件修改的任务。
错误类型若 DSL 语法错误或属性未定义,配置阶段失败。构建终止,不进入执行阶段。
性能影响配置阶段耗时随项目数量和脚本复杂度增加。应避免在此阶段进行耗时操作(如网络请求)。

注意事项:

  • 所有任务无论是否执行都会经历配置阶段。
  • 配置代码应尽量轻量,避免 I/O 或复杂计算。
  • 使用惰性配置 API(如 tasks.register)可优化性能。

3.3 执行阶段(Execution)

概念名称说明注意事项
执行阶段第三阶段,按依赖顺序执行命令行指定的任务。仅执行计划中的任务。
任务执行图(Task Graph)Gradle 根据依赖关系构建任务执行顺序。自动处理 dependsOn、mustRunAfter 等关系。
动作执行任务的 doFirst 和 doLast 闭包在此阶段按序执行。实际工作(如编译、复制)发生在此处。
增量构建判断Gradle 检查任务输入输出,若未变化则标记为 UP-TO-DATE。跳过执行,提升速度。
依赖下载若任务需要依赖(如 compile),此时从仓库下载。首次构建可能较慢。
失败处理若某任务失败,默认终止构建。使用 --continue 可继续执行其他独立任务。
日志输出显示任务执行状态(:taskName SUCCESS)。可通过 -i-d 查看详细日志。
并行执行若启用并行(org.gradle.parallel=true),独立任务可并发运行。提升多核机器构建效率。
finalizedBy 执行被 finalize 的任务无论原任务成功与否都会执行。常用于清理或报告。
缓存使用若启用构建缓存,尝试复用远程或本地缓存输出。减少重复构建。

注意事项:

  • 任务动作中可访问配置阶段确定的属性。
  • 避免在动作中修改任务输入,可能导致缓存失效。
  • 执行阶段是唯一可进行 I/O 和外部调用的阶段。

3.4 生命周期钩子(project.afterEvaluate, gradle.taskGraph.whenReady 等)

钩子方法语法用途代码示例注意事项
project.afterEvaluateproject.afterEvaluate { ... }在项目配置完成后执行afterEvaluate { println "Project ${name} configured" }用于修改被插件配置后的任务
allprojects.afterEvaluateallprojects { afterEvaluate { ... } }对所有项目(含子项目)执行allprojects { afterEvaluate { applyCommonConfig() } }确保子项目配置完成后再干预
gradle.projectsEvaluatedgradle.projectsEvaluated { ... }所有项目配置完成后执行gradle.projectsEvaluated { tasks.withType(Test) { maxHeapSize = '2g' } }适合跨项目统一配置
gradle.taskGraph.whenReadygradle.taskGraph.whenReady { ... }任务执行图构建完成后执行gradle.taskGraph.whenReady { if (it.hasTask(build)) { println "Build is running" } }可查询将要执行的任务
gradle.buildStartedgradle.buildStarted { ... }构建开始时执行(极少使用)gradle.buildStarted { startTime = System.currentTimeMillis() }通常用日志监听器替代
gradle.buildFinishedgradle.buildFinished { ... }构建结束时执行,无论成功失败gradle.buildFinished { result -> println "Build ${result.result}" }result 包含构建状态
Task Configuration Avoidancetasks.register('myTask') { ... }惰性创建任务,仅在需要时配置tasks.register('gen') { doLast { generateFile() } }推荐替代 tasks.create
Project Evaluation Listenergradle.addProjectEvaluationListener(...)监听项目评估开始/结束class MyListener implements ProjectEvaluationListener { ... }高级 API,用于插件开发
Task Execution Listenergradle.taskGraph.addTaskExecutionListener(...)监听任务执行开始/结束taskGraph.addTaskExecutionListener(new TaskLogger())用于性能监控或日志

注意事项:

  • afterEvaluate 是最常用的钩子,用于处理插件修改后的配置。
  • whenReady 中可安全查询任务图,适合条件逻辑。
  • 监听器应在配置阶段注册,否则可能错过事件。
  • 避免在钩子中执行耗时操作,影响构建性能。
  • 推荐优先使用惰性 API(register)而非立即创建(create)。

第四章:Project 对象与 API 使用

4.1 Project 接口核心属性与方法

方法/属性名称语法用途代码示例注意事项
project(隐式对象)表示当前项目,所有脚本中默认可用println project.name在 build.gradle 中可省略 project 前缀
nameproject.name获取项目名称(默认为目录名)println name可在 settings.gradle 中修改
projectDirproject.projectDir返回项目根目录的 File 对象println projectDir.absolutePath不可重新赋值
buildDirproject.buildDir返回构建输出目录(默认为 projectDir/build)buildDir = file('out')可自定义路径
rootProjectproject.rootProject获取根项目对象println rootProject.name在子项目中访问根项目
parentproject.parent获取父项目对象(子项目可用)if (parent != null) { ... }根项目返回 null
childrenproject.children返回子项目集合parent.children.each { println it.name }用于遍历子项目
propertiesproject.properties返回项目所有属性的只读 Mapprintln properties['version']包括系统属性、ext 属性等
loggerproject.logger获取日志记录器,用于输出信息logger.quiet 'Quiet message'
logger.info 'Info message'
logger.debug 'Debug message'
支持 quiet, info, debug, error 等级别
file()file('path')将路径字符串转为 File 对象file('src/main/java')相对路径基于 projectDir
files()files('a', 'b', 'c')创建 FileCollection 对象def srcFiles = files('src1', 'src2')可包含多个文件或目录
uri()uri('path')将路径转为 URI 对象uri('file:///path')用于网络或绝对路径处理
hasProperty()hasProperty('propName')检查属性是否存在if (hasProperty('customProp')) { ... }避免访问未定义属性出错
findProperty()findProperty('propName')查找属性值,不存在返回 nulldef val = findProperty('version')比直接访问更安全

注意事项:

  • project 对象在 build.gradle 中是隐式的,通常省略前缀。
  • buildDir 默认为 projectDir/build,可全局修改(如 allprojects { buildDir = 'out' })。
  • 使用 logger 而非 println 可控制日志级别输出。
  • file() 和 files() 是处理文件路径的标准方式,支持相对路径和 File 对象混合。

4.2 属性访问与扩展(ext)

方法/属性名称语法用途代码示例注意事项
ext 属性块ext { ... }批量定义扩展属性ext { version = '1.0'; enabled = true }类似定义多个 ext.prop = value
ext.属性 = 值ext.customProp = value定义单个扩展属性ext.myVersion = '2.0'可在任意位置定义
访问 ext 属性project.ext.propext.prop读取扩展属性println ext.myVersion在同一项目中可直接访问
hasProperty()hasProperty('extProp')检查 ext 属性是否存在if (hasProperty('myVersion')) { ... }推荐用于条件判断
findProperty()findProperty('extProp')安全查找属性(含 ext)def v = findProperty('myVersion')不存在返回 null,避免异常
父项目属性rootProject.ext.prop访问根项目定义的 ext 属性ext.version = rootProject.ext.appVersion常用于多项目版本统一
gradle.properties在 gradle.properties 文件中定义属性version=1.0
org=company
自动加载为项目属性支持 project 和 rootProject 级
系统属性systemProp.name-Dname=value通过 JVM 系统属性传参systemProp.http.proxyHost=proxy在 gradle.properties 或命令行设置
项目属性-PpropName=value命令行传入项目属性gradle build -Penv=prod在脚本中用 hasProperty/env 访问
属性优先级ext < gradle.properties < 命令行 -P < 系统属性属性覆盖顺序ext.version = '1.0'
// -Pversion=2.0 会覆盖
命令行动态值优先级最高

注意事项:

  • ext 是定义自定义属性的标准方式,避免污染全局命名空间。
  • 多项目中推荐在根项目 gradle.properties 或 ext 中定义共享属性。
  • 使用 hasProperty() 或 findProperty() 避免因属性缺失导致构建失败。
  • gradle.properties 文件可存在于项目根目录或用户主目录(~/.gradle/gradle.properties)。

4.3 文件操作(file, files, copy, sync 等)

方法名称语法用途代码示例注意事项
file()file('path')创建 File 对象def f = file('build.gradle')路径相对于 projectDir
files()files('a', 'b', 'c')创建 FileCollectiondef src = files('src1', 'src2')支持 List、Set、FileTree
copy()copy { ... }执行文件复制操作copy { from 'src'; into 'dest' }在任务动作中调用
Copy 任务task copyTask(type: Copy)创建可复用的复制任务task copyJar(type: Copy) { from jar; into 'dist' }支持增量构建
sync()sync { ... }复制并删除目标目录多余文件sync { from 'html'; into 'www' }保证目标目录与源完全一致
Sync 任务task syncAssets(type: Sync)创建同步任务task syncFiles(type: Sync) { ... }比 copy 更严格
from()from 'srcDir'from(files)指定复制源from 'src/main/resources'
from configurations.runtime
支持多种输入源
into()into 'destDir'指定复制目标目录into 'build/resources'目录不存在会自动创建
include()include '**/*.txt'包含匹配的文件include '**/*.java'支持 Ant 风格模式
exclude()exclude '**/*.tmp'排除匹配的文件exclude { it.name.startsWith('test') }可用闭包进行复杂判断
rename()rename 'old.txt', 'new.txt'重命名文件rename '(.)_V(.).txt', '1_2.txt'支持正则表达式
filter()filter(ReplaceTokens, tokens: [key: 'value'])替换文件内容占位符filter(ReplaceTokens, tokens: [version: version])常用于模板文件
expand()expand([key: 'value'])展开属性到文件内容expand([appVersion: version])类似 filter,用于 Groovy 模板
eachFile()eachFile { it.path = it.path.replace('old', 'new') }遍历并修改文件路径或属性eachFile { println it.name }可动态调整文件处理

注意事项:

  • copy 和 sync 通常在任务的 doLast 中调用,或定义为 Copy/Sync 类型任务。
  • Sync 任务会清理目标目录中源目录没有的文件,使用时注意数据丢失风险。
  • from 可接受任务(如 from jar),实现任务间输出传递。
  • 文件操作支持延迟计算(如闭包返回路径),适合动态路径。

4.4 目录与路径管理(projectDir, buildDir 等)

属性/方法名称语法用途代码示例注意事项
projectDirproject.projectDir项目根目录println projectDir只读,不可修改
buildDirproject.buildDir构建输出目录buildDir = file('output')可重新赋值,影响所有输出
rootDirrootProject.projectDir多项目构建的根目录println rootDir单项目中与 projectDir 相同
gradle.gradleUserHomeDirgradle.gradleUserHomeDirGradle 用户主目录(~/.gradle)println gradle.gradleUserHomeDir存放缓存、Wrapper 等
gradle.gradleHomeDirgradle.gradleHomeDirGradle 安装目录(非 Wrapper 时)println gradle.gradleHomeDirWrapper 下可能为空
layout.projectDirectorylayout.projectDirectoryProjectLayout 中的项目目录layout.projectDirectory.dir('src')用于插件开发
layout.buildDirectorylayout.buildDirectoryProjectLayout 中的构建目录layout.buildDirectory.dir('tmp')支持惰性求值
file()file('path')创建基于 projectDir 的文件对象file('src/main/java')推荐路径操作方式
mkdir()mkdir 'dirName'创建目录mkdir 'build/custom'目录已存在不报错
delete()delete 'path'delete(files)删除文件或目录delete buildDir
delete('temp')
支持通配符和 FileCollection
temporaryDirproject.temporaryDir获取临时目录(用于任务中间文件)def tmp = temporaryDir每次构建可能不同,自动清理

注意事项:

  • buildDir 修改应在配置阶段早期完成,避免任务已引用旧路径。
  • delete 是常用清理操作,可替代 clean 任务部分功能。
  • temporaryDir 适合存放任务中间产物,构建后自动清理。
  • 多项目中 rootDir 统一指向根项目目录,便于资源定位。
  • 路径操作优先使用 file() 和 layout API,保证可移植性。

第五章:Task 进阶用法

5.1 自定义任务类型(class extends DefaultTask)

方法/注解语法用途代码示例注意事项
DefaultTaskclass MyTask extends DefaultTask创建自定义任务基类abstract class MyTask extends DefaultTask { }必须继承以获得 Gradle 任务能力
@TaskAction@TaskAction def run() { ... }定义任务的执行动作@TaskAction def greet() { println 'Hello' }每个任务类只能有一个 @TaskAction 方法
构造函数MyTask() { ... }初始化任务属性MyTask() { group = 'custom' }可设置默认 group、description
属性定义@Input String message定义可配置属性String message = 'Hi'可在任务配置块中赋值
任务注册tasks.register('greet', MyTask)注册自定义任务实例tasks.register('sayHi', MyTask) { message = 'Hello' }推荐使用 register 实现惰性创建
任务创建tasks.create('greet', MyTask)立即创建任务实例tasks.create('sayHi', MyTask) { message = 'Hey' }立即执行配置
闭包委托doLast { } 中访问任务属性在动作中使用任务字段doLast { println message }动作闭包委托给任务实例
抽象任务类abstract class BaseTask extends DefaultTask定义共享逻辑的基类abstract class BaseTask extends DefaultTask { @TaskAction def exec() }子类继承并实现具体行为
依赖插件任务dependsOn compileJava在自定义任务中依赖内建任务task myTask { dependsOn 'compileJava' }确保前置任务完成
访问 ProjectgetProject()在任务类中获取所属项目println getProject().name通过继承 DefaultTask 获得

注意事项:

  • 自定义任务类通常放在 buildSrc/src/main/groovy 或单独模块中。
  • @TaskAction 方法是任务执行的入口,不可有参数。
  • 属性应使用 @Input、@Output 等注解以支持增量构建。
  • 推荐使用 tasks.register 而非 create 以提升性能。
  • 任务类文件需编译,确保 buildSrc 正确配置。

5.2 任务输入输出注解(@Input, @OutputFile 等)

注解名称语法用途代码示例注意事项
@Input@Input String version标记简单类型输入(String, Number, Boolean)@Input String getVersion() { return project.version }值变化时任务需重新执行
@InputFile@InputFile File configFile标记单个输入文件@InputFile File getInputFile() { return file('config.txt') }文件内容或元数据变化触发重建
@InputDirectory@InputDirectory File srcDir标记输入目录@InputDirectory File getSrc() { return file('src') }目录下任意文件变化均触发
@OutputFile@OutputFile File outputFile标记单个输出文件@OutputFile File getOutput() { return file('build/output.txt') }必须生成该文件,否则构建失败
@OutputDirectory@OutputDirectory File outDir标记输出目录@OutputDirectory File getOut() { return file('build/classes') }目录会被清理或检查
@Classpath@Classpath FileCollection classpath标记类路径输入(带顺序和可变性检查)@Classpath FileCollection getClasspath() { return configurations.compile }用于编译类路径
@CompileClasspath@CompileClasspath FileCollection cp优化的编译类路径(忽略内容哈希)@CompileClasspath FileCollection getCompileClasspath() { ... }提升 Java 编译任务性能
@Optional@Optional @OutputFile File report标记输出可选(可不存在)@Optional @OutputFile File getReport() { enabled ? file('report.txt') : null }避免因条件输出缺失报错
@Nested@Nested Config config标记嵌套的输入对象@Nested Map<String, Object> getOptions() { [encoding: 'UTF-8'] }内部字段变化也触发重建
Internal@org.gradle.api.tasks.Internal标记属性不参与增量判断@Internal String getTempDir() { return 'tmp' }用于临时或运行时属性

注意事项:

  • 必须为任务定义至少一个 @Input 和 @Output 才能支持增量构建。
  • @OutputFile 和 @OutputDirectory 标记的文件/目录必须被任务实际生成。
  • @Classpath 比 @InputFiles 更智能,能处理 jar 顺序和元数据。
  • 使用 @Optional 避免因条件输出导致的构建失败。
  • 注解必须用于 getter 方法或属性字段。

5.3 增量构建原理与实践

概念/方法说明代码示例注意事项
增量构建原理Gradle 在执行任务前检查其输入(@Input)和输出(@Output)是否变化。若未变,则跳过任务(UP-TO-DATE)。task process(type: ProcessTask) { inputDir = file('src'); outputFile = file('build/out.txt') }依赖正确使用输入输出注解
UP-TO-DATE任务输入输出未变,Gradle 跳过执行> Task :process UP-TO-DATE大幅提升构建速度
SKIP任务被显式跳过(如 onlyIf 条件为 false)> Task :skipTask SKIPPED与 UP-TO-DATE 不同
输入快照Gradle 为每个 @Input 属性创建快照(值、文件内容哈希等)自动生成存储在 .gradle/taskArtifacts/
输出快照为每个 @Output 记录文件状态自动生成构建后更新快照
首次构建无历史快照,所有任务必须执行gradle build输出被记录
第二次构建比较快照,未变任务标记为 UP-TO-DATEgradle build仅执行变化任务
清理影响delete buildDir 后快照丢失,下次全量构建gradle clean buildbuildDir 是默认输出目录
自定义比较逻辑通过注解控制比较行为(如 @PathSensitive)@InputDirectory @PathSensitivity(RELATIVE) File src忽略绝对路径差异
禁用增量tasks.named('myTask').get().outputs.upToDateWhen { false }outputs.upToDateWhen { false }强制任务每次都执行

注意事项:

  • 增量构建依赖正确的 @Input/@Output 注解。
  • 输出文件必须被任务实际生成,否则 Gradle 认为任务未完成。
  • 避免在任务动作中修改输入文件。
  • 使用 --info 查看任务是否被 UP-TO-DATE 跳过。
  • 多项目构建中,上游项目变更会触发下游重建。

5.4 任务条件执行(onlyIf)

方法名称语法用途代码示例注意事项
onlyIf(闭包)task.onlyIf { boolean }根据条件决定是否执行任务task release(type: Upload) { onlyIf { project.hasProperty('release') } }闭包返回 false 则跳过任务
onlyIf(内联)task.onlyIf { it.name.length() > 5 }在任务定义中设置条件processFiles.onlyIf { sourceDir.exists() }条件在执行阶段评估
多条件组合onlyIf { cond1 && cond2 }组合多个判断逻辑onlyIf { project.os == 'linux' && debugEnabled }使用 Groovy 逻辑操作符
访问任务属性onlyIf { hasProperty('deploy') }检查项目或任务属性onlyIf { findProperty('env') == 'prod' }常用 -P 传参控制
平台判断onlyIf { System.getProperty('os.name').contains('Windows') }按操作系统条件执行onlyIf { JavaVersion.current().isJava8() }用于跨平台构建
文件存在性onlyIf { file('config.yml').exists() }根据文件是否存在决定onlyIf { sourceFiles.files.any() }避免空输入错误
跳过状态SKIPPED任务被 onlyIf 跳过时的状态> Task :release SKIPPED区别于 FAILED 或 UP-TO-DATE
与 dependsOn 结合task A.dependsOn B; B.onlyIf { false }依赖任务被跳过,当前任务仍可执行若 A 不依赖 B 输出,A 仍执行但 A 可能因缺少输入失败
动态条件onlyIf { Math.random() > 0.5 }使用运行时动态值不推荐,破坏可重现性应基于稳定输入
移除条件task.onlyIf = null清除已设置的 onlyIf 条件release.onlyIf = null用于测试或动态控制

注意事项:

  • onlyIf 在执行阶段评估,配置阶段代码仍会执行。
  • 返回 false 时任务状态为 SKIPPED,不是 UP-TO-DATE。
  • 条件应基于稳定输入(属性、文件状态),避免随机值。
  • 被跳过任务的输出不会生成,依赖它的任务可能失败。
  • 可用于实现 release、deploy 等需手动触发的任务。

5.5 任务规则(TaskRule)

方法名称语法用途代码示例注意事项
addRuleproject.getTasks().addRule(...)添加动态任务规则project.tasks.addRule('Pattern: hello') { String taskName -> if (taskName.startsWith('hello')) { task(taskName) { doLast { println "Hello ${taskName - 'hello'}" } } } }匹配模式创建任务
规则描述String description规则的描述信息(可选)'Pattern: dist'在错误消息中显示
闭包参数{ String taskName -> ... }接收任务名,返回 Task 或 null{ name -> if (name == 'magic') task(name) { ... } }必须返回 Task 实例或 null
动态任务创建无显式定义的任务允许用户执行未定义的任务gradle helloWorld若规则匹配则自动创建
错误提示若无匹配规则且任务不存在报错:Task 'xxx' not found in root project提示可用任务或规则模式规则应有清晰描述
与静态任务优先级静态任务优先若 helloWorld 已定义,则规则不生效规则仅用于未定义任务避免冲突
多规则顺序按添加顺序匹配先添加的规则先尝试匹配可添加多个规则后续规则可能被跳过
移除规则不支持直接移除需设计为条件返回 nullrule = project.tasks.addRule(...) // 无法 removeGradle API 未提供 removeRule
使用场景生成版本化任务、批量任务dist2023, dist2024
buildModuleA, buildModuleB
减少重复定义
替代方案tasks.register with name mapping推荐使用惰性注册替代规则tasks.register("hello${name}") { ... }更现代、可控

注意事项:

  • 任务规则是遗留特性,官方推荐使用 tasks.register 动态创建任务。
  • 规则应在配置阶段早期添加。
  • 规则描述应清晰,帮助用户理解可用任务模式。
  • 返回 null 表示不处理该任务名,继续尝试其他规则或报错。
  • 由于无法移除规则,应谨慎使用,避免污染任务空间。

第六章:依赖管理(Dependencies)

6.1 依赖配置(configurations)

概念名称说明代码示例注意事项
Configuration依赖的逻辑分组,定义依赖的用途和可见性。configurations { myConfig }每个配置是一个 Configuration 对象
创建配置使用 configurations {} 块创建自定义配置configurations { integrationTestImplementation; integrationTestRuntimeOnly }通常用于测试源集或插件扩展
扩展配置extendsFrom 实现配置间继承debugImplementation.extendsFrom(implementation)子配置包含父配置的所有依赖
默认配置Gradle 和插件自动创建的标准配置implementation, api, testImplementation 等Java 插件提供主要配置
配置状态可被解析(resolve)、用于编译、打包等configurations.compileClasspath解析后形成依赖图
配置属性visible, transitive, extendsFrom, canBeResolved, canBeConsumedcanBeResolved = true控制配置行为
canBeResolved配置是否可被解析下载configurations.myConfig.canBeResolved = trueimplementation 不可解析,compileClasspath 可解析
canBeConsumed配置是否可被其他项目消费canBeConsumed = true发布时使用
visible是否对其他项目可见visible = true内部配置可设为 false
dependenciesOf查看某配置包含的依赖println configurations.implementation.allDependencies调试依赖关系
incoming访问已解析的依赖(文件)configurations.compileClasspath.incoming.files获取下载后的 jar 文件
outgoing访问对外发布的依赖信息outgoing.artifact jar用于发布配置

注意事项:

  • configurations 定义了依赖的作用域和生命周期。
  • canBeResolved=true 的配置(如 compileClasspath)才能触发依赖下载。
  • 自定义配置常用于多源集测试(如集成测试、性能测试)。
  • 避免直接修改内建配置的 canBeResolved 或 canBeConsumed,可能导致插件异常。

6.2 常用依赖配置(implementation, api, compileOnly, runtimeOnly 等)

配置名称用途传递性是否参与编译是否打包是否暴露给使用者代码示例注意事项
api声明对外公开的 API 依赖✅ 传递✅ 是dependencies { api 'commons-lang:commons-lang3:3.12.0' }适用于库项目,使用者也能访问
implementation声明内部实现依赖❌ 不传递❌ 否dependencies { implementation 'com.google.guava:guava:31.1-jre' }推荐用于大多数依赖,减少传递污染
compileOnly仅用于编译,不打包也不传递dependencies { compileOnly 'javax.annotation:javax.annotation-api:1.3.2' }如 JSR-305 注解、Servlet API
runtimeOnly仅在运行时需要,不参与编译dependencies { runtimeOnly 'org.postgresql:postgresql:42.5.0' }如 JDBC 驱动、日志实现
testImplementation测试代码的实现依赖✅ (测试)✅ (测试)dependencies { testImplementation 'junit:junit:4.13.2' }JUnit、TestNG、Mockito 等
testCompileOnly仅测试编译时需要✅ (测试)dependencies { testCompileOnly 'org.junit.jupiter:junit-jupiter-api:5.9.2' }JUnit 5 API
testRuntimeOnly仅测试运行时需要✅ (测试)dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' }JUnit 5 引擎
annotationProcessor注解处理器依赖dependencies { annotationProcessor 'com.google.dagger:dagger-compiler:2.44' }用于 Lombok, Dagger, MapStruct 等
archives项目产生的构件(已过时)-----现在使用 components.java 发布
default默认配置,包含所有可消费的依赖-compile project(':sub') 等旧语法用于旧版项目依赖

注意事项:

  • implementation 是首选,它隐藏内部依赖,提升构建性能和封装性。
  • api 仅在你明确需要将依赖暴露给库的使用者时使用。
  • compileOnly 和 runtimeOnly 组合使用可精确控制依赖生命周期。
  • Java 9+ 模块化项目中,compileOnly 类似 requires static
  • 避免使用已废弃的 compile 配置。

6.3 添加外部依赖(dependencies 块)

方法语法用途代码示例注意事项
Module 依赖group: '', name: '', version: ''完整坐标声明dependencies { implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1' }最标准方式
简化语法'group:name:version'Groovy DSL 简化写法dependencies { implementation 'org.springframework:spring-core:5.3.21' }推荐,简洁易读
Map 语法[group: '', name: '', version: '']显式 Map 写法dependencies { testImplementation([group: 'org.mockito', name: 'mockito-core', version: '4.6.1']) }适合动态构造
动态版本'group:name:1.+''group:name:latest.integration'版本通配implementation 'log4j:log4j:1.2.+'
runtimeOnly 'mysql:mysql-connector-java:8.0.+'
不推荐,破坏可重现性
严格版本version { strictly 'x.y.z' }强制指定版本implementation('com.fasterxml.jackson.core:jackson-databind') { version { strictly '2.13.3' } }覆盖传递依赖的版本
排除传递依赖exclude module: 'module-name'移除特定传递依赖implementation('org.hibernate:hibernate-core:5.6.10.Final') { exclude module: 'slf4j-api' }解决冲突或减少包体积
排除所有传递依赖transitive = false关闭传递性implementation('com.google.code.gson:gson:2.8.9') { transitive = false }仅引入直接依赖
分类器(classifier)classifier: 'sources''javadoc'指定构件分类compileOnly 'com.example:lib:1.0:tests'如源码、文档、特定平台库
BOM 导入platform()enforcedPlatform()导入版本管理 BOMdependencies { implementation platform('org.springframework.boot:spring-boot-dependencies:2.7.0'); implementation 'org.springframework.boot:spring-boot-starter-web' }统一管理版本,避免冲突
Kotlin DSLimplementation("group:name:version")在 .gradle.kts 中使用dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib:1.7.10") }使用括号和引号

注意事项:

  • 推荐使用简化语法 'group:name:version'
  • 避免动态版本(1.+),应使用固定版本保证构建可重现。
  • 使用 exclude 或 transitive = false 解决依赖冲突或瘦身。
  • platform() 允许升级,enforcedPlatform() 强制锁定,按需选择。
  • BOM 是管理大型项目依赖版本的最佳实践。

6.4 依赖版本管理与冲突解决

方法/概念说明代码示例注意事项
冲突原因多个路径引入同一模块不同版本A → C:1.0, B → C:2.0Gradle 需决定使用哪个版本
冲突解决策略最高版本优先(默认)若无其他规则,使用 2.0简单但可能引入不兼容版本
强制版本(force)强制使用指定版本implementation('log4j:log4j:1.2.17') { force = true }覆盖所有传递依赖中的版本
严格版本(strictly)声明所需版本,拒绝其他version { strictly '1.2.17' }若有冲突则构建失败,需手动解决
版本目录(Version Catalogs)在 gradle/libs.versions.toml 中集中管理版本[versions] guava = "31.1-jre"
[libraries] guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
推荐,集中、类型安全、易于升级
使用 Catalogs在 build.gradle 中引用dependencies { implementation libs.guava }通过 libs 访问
依赖约束(dependencyConstraints)在平台或项目中声明约束dependencyConstraints { constraint('com.fasterxml.jackson.core:jackson-databind') { version { strictly '[2.12.0, 2.14.0)'; prefer '2.13.3' } } }更灵活的版本控制
查看依赖树gradle dependencies输出所有配置的依赖树gradle dependencies --configuration implementation
特定配置树--configuration <name>查看指定配置的依赖gradle dependencies --configuration runtimeClasspath
忽略版本changing = true标记依赖为动态(如 SNAPSHOT)implementation('com.mycompany:lib:1.0-SNAPSHOT') { changing = true }
锁定文件(dependencyLocking)生成 lock 文件锁定版本gradle dependencies --write-locks保证 CI/CD 环境一致性
禁用传递依赖transitive = false阻止传递implementation('org.hibernate:hibernate-core') { transitive = false }

注意事项:

  • 版本目录(Version Catalogs)是现代 Gradle 推荐的版本管理方式。
  • 优先使用 strictly 或 prefer 进行约束,而非 force(过于强硬)。
  • 定期运行 gradle dependencies 分析依赖树,避免”依赖地狱”。
  • 在 CI/CD 中使用锁定文件确保构建一致性。
  • changing = true 仅用于 SNAPSHOT 或动态构建,避免在生产环境滥用。

6.5 本地文件依赖与项目依赖(project(‘:xx’))

依赖类型语法用途代码示例注意事项
本地 JAR 依赖files('libs/a.jar')fileTree添加本地 jar 文件dependencies { implementation files('libs/utils.jar'); implementation fileTree('libs') }不推荐,难于管理
本地目录依赖fileTree(dir: 'prebuilt', include: '*.jar')从目录加载多个 jardependencies { runtimeOnly fileTree(dir: 'drivers', include: '*.jar') }适合第三方驱动
项目依赖(同构)project(':subproject')依赖同一构建中的子项目dependencies { implementation project(':common'); testImplementation project(':testing-utils') }子项目需在 settings.gradle 中 include
项目依赖(异构)project(path: ':web', configuration: 'shadow')依赖子项目的特定配置implementation project(path: ':service', configuration: 'shadowJar')用于自定义构件
项目依赖传递性取决于配置api 传递,implementation 不传递子项目 A 的 api 依赖会传递给依赖 A 的项目与外部依赖行为一致
多项目构建settings.gradle 中 include组织多个相关项目include 'web', 'service', 'common'根项目协调依赖和版本
构建顺序Gradle 自动确定基于项目依赖关系无需手动指定自动处理
依赖替换(dependencySubstitution)resolutionStrategy.eachDependency强制使用项目依赖dependencySubstitution { substitute module('com.mycompany:common') with project(':common') }用于本地开发调试远程库
文件依赖缺点无法传递、难于版本控制--不支持传递依赖,团队协作困难
项目依赖优点支持增量构建、传递性、版本一致--修改子项目会触发上游重建,开发效率高

注意事项:

  • 尽量使用项目依赖而非本地文件,便于维护和传递。
  • 本地 JAR 依赖应放入版本控制或私有仓库,避免路径问题。
  • project(‘:sub’) 默认使用子项目的 default 配置,通常映射到 implementation 或 api。
  • 在 resolutionStrategy 中使用 dependencySubstitution 可实现”本地覆盖远程”,方便调试。
  • 多项目构建是组织大型应用或微服务的理想方式。

第七章:多项目构建(Multi-project Builds)

7.1 settings.gradle 与 include

概念说明代码示例注意事项
settings.gradle根项目中的配置文件,用于定义多项目结构,在初始化阶段执行// settings.gradle
rootProject.name = 'myapp'
include 'core', 'web', 'service'
必须位于根项目目录
rootProject.name设置根项目名称rootProject.name = 'enterprise-app'默认为根目录名
include声明子项目,创建项目实例include 'moduleA'
include ':utils', ':api'
路径使用 : 分隔
includeFlat包含同一层级的子项目(平级目录)includeFlat 'shared-lib', 'tools'子项目与 settings.gradle 同目录
projectDir 自定义修改子项目目录位置include ':database'
project(':database').projectDir = new File(settingsDir, '../external/db')
灵活组织项目结构
动态 include使用 Groovy 逻辑动态包含项目file('modules').listFiles().each { if (it.isDirectory()) { include ":${it.name}" } }适合模块化项目
复合构建(Composite Build)将独立构建合并为一个整体includeBuild '../library'
includeBuild 'https://github.com/user/repo.git'
可替换依赖为源码构建
buildSrc特殊子项目,存放构建脚本代码// 目录结构:buildSrc/ src/main/groovy/... build.gradle自动编译并加入构建 classpath
初始化脚本-I 参数指定 init.gradle,影响所有构建gradle -I init.gradle build企业级全局配置

注意事项:

  • settings.gradle 是多项目构建的入口,必须存在。
  • include 定义的路径是项目路径(project path),不一定是文件系统路径。
  • buildSrc 是一个独立的 Gradle 构建,用于扩展 Gradle 本身。
  • 复合构建可用于同时开发多个相关库。

7.2 子项目结构与配置

概念说明代码示例注意事项
子项目目录每个子项目有独立目录,包含自己的 build.gradlemyapp/
├── settings.gradle
├── core/
│ └── build.gradle
└── web/
└── build.gradle
推荐结构
子项目 build.gradle配置该项目的插件、依赖、任务等// web/build.gradle
apply plugin: 'java'
dependencies { implementation project(':core') }
独立于其他项目
插件应用在子项目中应用特定插件apply plugin: 'java-library'
apply plugin: 'war'
按需启用功能
属性继承子项目可访问根项目属性// 在子项目中:
println rootProject.name
version = rootProject.ext.version
推荐共享版本号
项目特定配置为子项目设置唯一配置// 在 core/build.gradle 中:
sourceCompatibility = 11
允许差异化
测试源集每个子项目可有自己的测试test { useJUnitPlatform() }独立运行测试
构建输出隔离子项目的构建输出默认在各自 buildDirbuildDir = "out" // 影响当前项目避免冲突
资源文件子项目管理自己的资源src/main/resources/config.properties打包时独立处理
自定义任务在子项目中定义专用任务task deploy { ... } // 仅 web 项目有按需扩展
多语言支持不同子项目可用不同技术栈core: Java, web: Kotlin, mobile: Android提升灵活性

注意事项:

  • 每个子项目是相对独立的构建单元。
  • 应尽量保持子项目职责单一(SRP)。
  • 避免子项目间过度耦合。
  • 使用统一的代码风格和构建规范。

7.3 项目间依赖

依赖类型语法用途代码示例注意事项
内部项目依赖project(':subproject')依赖同一构建中的子项目dependencies { implementation project(':common') }子项目需在 settings.gradle 中声明
api 传递依赖api project(':lib')对外暴露依赖// 在 utils 项目中:
api project(':logging')
// 则使用 utils 的项目也能访问 logging
类似 Maven 的 compile
implementation 依赖implementation project(':model')内部实现依赖,不传递dependencies { implementation project(':database') }推荐方式,减少传递污染
测试依赖testImplementation project(':test-utils')仅测试时依赖testImplementation project(path: ':testing', configuration: 'default')隔离测试辅助代码
运行时依赖runtimeOnly project(':plugin-system')运行时需要,编译时不参与runtimeOnly project(':report-engine')如插件、驱动
强制特定配置project(path: ':sub', configuration: 'shadow')使用子项目的自定义配置implementation project(path: ':web', configuration: 'archives')用于 fat jar 等场景
循环依赖检测Gradle 自动检测A → B, B → A构建失败,提示循环依赖应重构避免
构建顺序Gradle 自动确定依赖项目先构建无需手动指定基于任务依赖图
传递性行为与外部依赖一致implementation 不传递,api 传递统一模型,易于理解行为一致
查看依赖树gradle dependencies分析项目依赖关系gradle :web:dependencies --configuration runtimeClasspath调试依赖问题

注意事项:

  • 项目依赖会触发被依赖项目的构建。
  • 使用 implementation 而非 api 以降低耦合。
  • 避免循环依赖,可通过引入中间模块解决。
  • 项目依赖支持增量构建,修改子项目会触发上游重建。

7.4 共享配置与约定(allprojects, subprojects)

方法语法用途代码示例注意事项
allprojectsallprojects { ... }配置所有项目(含根项目)allprojects { version = '1.0.0'; group = 'com.example' }根项目也受影响
subprojectssubprojects { ... }仅配置子项目(不含根项目)subprojects { apply plugin: 'java'; java.sourceCompatibility = JavaVersion.VERSION_11 }更常用
集中式依赖管理在根项目定义 ext 或使用 versions.tomlext { junitVersion = '5.9.2' }
// 子项目中:testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
统一版本
共享仓库在 allprojects 中定义 repositoriesallprojects { repositories { mavenCentral(); google() } }避免重复配置
共享插件在 subprojects 中应用公共插件subprojects { apply plugin: 'checkstyle'; checkstyle.toolVersion = '10.3' }统一代码质量工具
共享任务定义通用任务subprojects { task printName { doLast { println name } } }所有子项目都有该任务
条件配置结合 if 判断项目名称subprojects { if (name.contains('web')) { apply plugin: 'war' } }实现差异化配置
配置顺序先 allprojects,后 subprojects,再项目自身allprojects { ... }; subprojects { ... }; // 子项目 build.gradle 覆盖后定义优先
约定优于配置设立团队构建规范allprojects { tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } }提升一致性
使用 Catalogs 共享在 libs.versions.toml 中定义[libraries] junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version = "5.9.2" }
// 子项目:dependencies { testImplementation libs.junit.api }
现代推荐方式

注意事项:

  • allprojects 和 subprojects 应写在根项目的 build.gradle 中。
  • 推荐使用 Version Catalogs (gradle/libs.versions.toml) 进行集中式依赖管理。
  • 共享配置应尽量简洁,避免过度约束。
  • 子项目可覆盖共享配置以满足特殊需求。

第八章:插件(Plugins)使用与开发

8.1 插件的作用与分类(二进制 vs 脚本插件)

概念说明代码示例注意事项
插件作用封装可复用的构建逻辑,如任务、约定、依赖配置等apply plugin: 'java' // 添加 Java 编译、测试等任务提升构建脚本可维护性
二进制插件编译后的类(JAR),实现 Plugin 接口,功能强大class MyPlugin implements Plugin { void apply(Project project) { project.task('hello') { ... } } }可发布到仓库,团队共享
脚本插件.gradle 文件,包含可被其他脚本应用的配置代码// common.gradle
apply plugin: 'java'; group = 'com.example'; version = '1.0'
适用于项目内共享配置
内建插件Gradle 自带插件(如 java, war, kotlin)apply plugin: 'java-library'无需额外依赖
社区插件Gradle Plugin Portal 上的第三方插件id 'org.springframework.boot' version '3.1.0'丰富生态系统
插件 ID唯一标识符,用于应用插件'java', 'com.android.application'通常为反向域名
应用时机插件在配置阶段被应用,修改项目结构apply from: 'script.gradle'
apply plugin: 'my.plugin'
应用后立即执行逻辑
插件幂等性同一插件多次应用通常只生效一次apply plugin: 'java'; apply plugin: 'java' // 无副作用避免重复配置
插件依赖插件可依赖其他插件自动应用plugins { id 'java' } // 自动应用 'jvm-component' 等减少手动配置
buildSrc 插件在 buildSrc 中开发的二进制插件// buildSrc/src/main/groovy/MyPlugin.groovy; class MyPlugin implements Plugin仅对当前构建可用

注意事项:

  • 二进制插件适合跨项目复用,脚本插件适合项目内共享。
  • 插件应在 build.gradle 的早期应用,确保后续配置生效。
  • 避免在插件中执行耗时操作,影响配置阶段性能。
  • 脚本插件使用 apply from:,二进制插件使用 apply plugin:plugins {}

8.2 应用官方插件(apply plugin: ‘java’)

插件名称作用应用方式添加的任务注意事项
java标准 Java 项目构建apply plugin: 'java'compileJava, processResources, classes, test, jar, javadoc基础插件,提供编译、测试、打包
java-libraryJava 库项目(支持 api/implementation)apply plugin: 'java-library'同 java,但配置更细粒度推荐用于发布库
war构建 WAR 包(Web 应用)apply plugin: 'war'war, compileJsp依赖 java 插件
application可执行 JVM 应用apply plugin: 'application'startScripts, installDist, run需设置 mainClass
groovyGroovy 项目支持apply plugin: 'groovy'compileGroovy, compileTestGroovy替代 java 插件
scalaScala 项目支持apply plugin: 'scala'compileScala, compileTestScala需配置 Scala 版本
kotlin-jvmKotlin JVM 项目apply plugin: 'kotlin'compileKotlin, compileTestKotlin需添加 kotlin-gradle-plugin 依赖
eclipse生成 Eclipse 项目文件apply plugin: 'eclipse'eclipse, eclipseClasspath, eclipseProject用于 IDE 集成
idea生成 IntelliJ IDEA 文件apply plugin: 'idea'idea, ideaModule, ideaProject推荐使用 IDEA 直接导入
signing签名构件(如 JAR)apply plugin: 'signing'signArchives, signMavenJavaPublication发布到 Maven Central 所需
maven-publish发布构件到 Maven 仓库apply plugin: 'maven-publish'publish, publishToMavenLocal现代发布方式

注意事项:

  • 大多数插件会自动应用其前置插件(如 war 自动应用 java)。
  • 应用插件后,会自动创建源集(sourceSets)、任务、配置等。
  • 插件文档是了解其功能的最佳来源。
  • 避免同时应用冲突的插件(如 java 和 android-library)。

8.3 使用插件 DSL(plugins block)

特性说明代码示例注意事项
plugins {} 块新的插件应用方式,位于 build.gradle 顶部plugins { id 'java-library'; id 'org.springframework.boot' version '3.1.0' }必须在文件顶部,无前置语句
插件版本声明在 plugins 块中直接指定版本id 'com.github.johnrengelman.shadow' version '8.1.1'简化依赖管理
插件解析从 Gradle Plugin Portal 或自定义仓库下载仓库配置在 settings.gradle 中可配置 pluginManagement
优势:性能插件在配置前解析,提升性能-比 apply plugin 更快
优势:简洁一行声明插件和版本id 'java'无需 buildscript 块
优势:约束强制插件版本集中管理-减少版本冲突
插件管理(pluginManagement)在 settings.gradle 中集中管理插件版本// settings.gradle; pluginManagement { plugins { id 'org.springframework.boot' version '3.1.0' } repositories { gradlePluginPortal(); mavenCentral() } }全局统一版本
与 buildscript 对比旧方式需在 buildscript.dependencies 中声明buildscript { dependencies { classpath 'org.springframework.boot:spring-boot-gradle-plugin:3.1.0' } }; apply plugin: 'org.springframework.boot'plugins {} 更现代
限制:不可条件应用plugins {} 不支持 if 等条件逻辑条件应用仍需 apply(plugin: 'id')对于动态插件需使用 apply
插件别名在 versions.toml 中定义别名[plugins] spring-boot = { id = "org.springframework.boot", version = "3.1.0" }
// build.gradle: plugins { alias(libs.plugins.spring.boot) }
提升可维护性

注意事项:

  • plugins {} 是推荐的现代方式,应优先使用。
  • 必须放在 build.gradle 文件的最顶部,前面不能有任何语句(注释除外)。
  • 无法在 plugins {} 中使用项目属性或条件逻辑。
  • 对于需要动态决定是否应用的插件,仍需使用 apply(plugin: 'id')

8.4 自定义插件开发(实现 Plugin 接口)

方法/概念说明代码示例注意事项
实现 Plugin 接口创建类实现 Plugin<T>,T 通常是 Projectclass GreetingPlugin implements Plugin { void apply(Project project) { project.task('hello') { doLast { println "Hello from ${project.name}" } } } }核心入口
apply 方法插件被应用时执行的逻辑void apply(Project project) { ... }可访问项目对象,添加任务、配置等
插件 ID通过 META-INF 定义// resources/META-INF/gradle-plugins/com.example.greeting.properties; implementation-class=com.example.GreetingPlugin文件名即 ID
插件属性文件声明实现类的全限定名implementation-class=com.example.MyPlugin位于 buildSrc 或独立模块
添加任务在 apply 中创建任务project.tasks.register('customTask') { doLast { ... } }推荐使用 register
配置扩展(Extension)为插件提供配置 DSLproject.extensions.create('greeting', GreetingExtension)
// 使用:greeting { message = 'Hi' }
提升可用性
扩展类定义定义配置属性class GreetingExtension { String message = 'Hello'; String subject = 'World' }可在 build.gradle 中配置
访问扩展在任务中读取用户配置project.tasks.register('sayHello') { doLast { def ext = project.extensions.getByType(GreetingExtension); println "${ext.message} ${ext.subject}" } }解耦配置与逻辑
应用插件在项目中使用自定义插件plugins { id 'com.example.greeting' }需确保插件在 classpath
buildSrc 开发在 buildSrc 中直接编写插件buildSrc/src/main/groovy/com/example/GreetingPlugin.groovy仅对当前构建有效,无需发布
独立模块开发创建独立的 Java/Groovy 模块开发插件新建项目,添加 gradleApi() 依赖可发布到私有或公共仓库

注意事项:

  • 插件类必须有公共无参构造函数。
  • 使用 project.extensions.create() 添加配置 DSL,提升用户体验。
  • 推荐在 buildSrc 中快速开发和测试插件。
  • 发布前进行充分测试,确保兼容性。
  • 文档化插件的使用方法和配置选项。

8.5 插件的发布与复用

方法说明代码示例注意事项
发布到 Gradle Plugin Portal官方插件仓库,便于分享使用 gradlePlugin DSL 和 publishPlugins 任务需注册账号,审核机制
发布到 Maven 仓库私有或公共 Maven 仓库(如 Nexus)publishing { publications { maven(MavenPublication) { from components.java } } repositories { maven { url "https://repo.mycompany.com"; credentials { ... } } } }企业内部常用
插件元数据包含 ID、实现类、标签、网站等// plugin.xml 或 build.gradle 配置影响在 Portal 中的展示
使用插件标记(markers)发布独立的插件标记模块publishPluginMarkerMavenPublication // 自动生成简化版本管理
版本管理语义化版本(SemVer)1.0.0, 1.0.1, 2.0.0重大变更应升级主版本
在其他项目中使用通过 plugins {} 应用已发布的插件plugins { id 'com.example.myplugin' version '1.2.0' }需能访问仓库
本地测试发布使用 mavenLocal() 测试publishing { repositories { mavenLocal() } }
// 测试项目:plugins { id 'com.example.plugin' version '1.0.0' }
验证发布流程
插件文档编写 README 和使用说明// src/docs/asciidoc/guide.adoc提高可用性
依赖管理插件自身的依赖dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3'; gradleApi(); localGroovy() }避免传递不必要的依赖
兼容性测试测试不同 Gradle 版本在多个 Gradle 版本下运行测试确保向后兼容

注意事项:

  • 发布前确保插件稳定、有文档、有测试。
  • 推荐发布到私有 Maven 仓库用于企业内部共享。
  • 发布到 Plugin Portal 适合开源项目。
  • 使用 gradleApi() 依赖 Gradle 自身 API,版本与构建环境一致。
  • 避免在插件中引入大型或不稳定的第三方库。

第九章:Gradle 与 Java 项目集成

9.1 Java 插件引入与默认任务

概念说明代码示例注意事项
应用 Java 插件启用 Java 项目构建功能plugins { id 'java' }
// 或旧方式:apply plugin: 'java'
必须应用插件才能使用 Java 任务
插件自动配置自动添加仓库、源集、任务等-无需手动创建 compileJava 等任务
默认源集创建 main 和 test 源集src/main/java, src/test/java遵循标准布局
核心任务:compileJava编译主源集 Java 代码gradle compileJava生成 class 文件到 build/classes/java/main
核心任务:compileTestJava编译测试源集代码gradle compileTestJava依赖 compileJava
核心任务:test编译并运行测试gradle test使用 JUnit 3/4/5 或 TestNG
核心任务:jar打包主源集为 JARgradle jar输出到 build/libs/
核心任务:javadoc生成 Java 文档gradle javadoc输出到 build/docs/javadoc
核心任务:clean删除 build 目录gradle clean清理构建输出
任务依赖关系任务间自动建立依赖test.dependsOn classes
jar.dependsOn classes
构建时自动触发前置任务
查看任务列出项目所有任务gradle tasks
gradle tasks --all
了解可用任务
生命周期任务build 聚合常用任务gradle build // 等价于:classes, test, jar推荐用于完整构建
工件(Artifacts)jar 任务生成的 JAR 文件自动注册为工件-可被其他项目依赖
Java 版本配置设置源和目标兼容性java { sourceCompatibility = JavaVersion.VERSION_11; targetCompatibility = JavaVersion.VERSION_11 }推荐使用 java 工件属性
默认仓库无默认仓库,需手动配置repositories { mavenCentral() }否则无法下载依赖

注意事项:

  • 应用 java 插件后,Gradle 会自动创建标准 Java 项目的构建模型。
  • build 任务是推荐的完整构建命令,包含编译、测试、打包。
  • 任务执行遵循依赖关系,调用 test 会自动执行 compileJava 和 compileTestJava。
  • 若需运行应用,需额外配置 JavaExec 任务或应用 application 插件。

9.2 源码目录结构配置(sourceSets)

概念说明代码示例注意事项
sourceSets定义源代码和资源的逻辑分组sourceSets { main { ... }; test { ... } }Java 插件默认创建 main 和 test
修改主源集自定义 main 的源目录sourceSets { main { java { srcDirs = ['src/main/java', 'generated/src'] }; resources { srcDirs = ['src/main/resources'] } } }可添加多个目录
添加测试源集自定义 test 目录sourceSets { test { java { srcDir 'src/test/java' } } }支持 JUnit/TestNG
创建自定义源集定义新源集(如 integrationTest)sourceSets { integrationTest { compileClasspath += main.output + test.runtimeClasspath; runtimeClasspath += output + compileClasspath } }; dependencies { integrationTestImplementation project(':common'); integrationTestRuntimeOnly 'org.h2:h2:2.1.214' }用于特殊测试类型
源集属性java, resources, output, compileClasspath, runtimeClasspathsourceSets.main.java.srcDirs
sourceSets.test.output.classesDirs
访问源集配置
添加依赖到源集为特定源集配置依赖dependencies { mainImplementation 'com.google.guava:guava:31.1-jre'; testImplementation 'org.mockito:mockito-core:4.6.1' }配置名格式:{sourceSet}{Configuration}
输出目录配置自定义编译输出路径sourceSets.main.output.classesDirs = new File(buildDir, 'custom-classes')默认在 build/classes
排除/包含文件过滤源文件sourceSets.main.java { exclude 'com/example/internal/'; include '**/Public*.java' }支持 Ant 风格模式
多语言支持在同一源集中混合语言sourceSets.main { java { srcDir 'src/main/java' }; resources { srcDir 'src/main/resources' } }Java 插件默认支持
源集任务每个源集生成独立的编译任务compileIntegrationTestJava, processIntegrationTestResources可单独执行

注意事项:

  • 自定义源集不会自动创建依赖配置,需手动定义(如 integrationTestImplementation)。
  • 需正确设置 compileClasspath 和 runtimeClasspath 以确保类路径完整。
  • 源集是组织代码的逻辑单元,可对应不同构建场景。
  • 修改 srcDirs 会覆盖默认目录,使用 srcDir 添加目录更安全。

9.3 编译、测试、打包配置

配置项说明代码示例注意事项
编译器选项配置 javac 参数tasks.withType(JavaCompile) { options.encoding = 'UTF-8'; options.compilerArgs << '-Xlint:unchecked'; options.release = 11 }推荐使用 options.release
增量编译Gradle 默认启用-修改的类及其依赖类会被重新编译
编译失败处理控制失败行为compileJava { options.failOnError = true; options.warnings = true }可关闭警告
测试配置配置 Test 任务test { useJUnitPlatform(); testLogging { events 'passed', 'skipped', 'failed' }; systemProperty 'property.name', 'value' }设置日志、系统属性
测试分组运行特定测试test { include '**/UserServiceTest.class'; exclude '**/*IntegrationTest.class' }使用 include/exclude
并行测试启用并行执行test { maxParallelForks = 4 }提升测试速度
测试报告生成 HTML 报告test { reports { html.required = true; junitXml.required = true } }默认生成 XML 和 HTML
打包配置配置 jar 任务jar { duplicatesStrategy = DuplicatesStrategy.EXCLUDE }处理重复文件
编译依赖implementation, api, compileOnlydependencies { implementation 'org.slf4j:slf4j-api:2.0.7'; compileOnly 'org.projectlombok:lombok:1.18.28' }正确使用配置
测试依赖testImplementation, testRuntimeOnlytestImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'; testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.9.2'JUnit 5 需要 engine
运行时依赖runtimeOnlyruntimeOnly 'com.h2database:h2:2.1.214'
runtimeOnly 'mysql:mysql-connector-java:8.0.33'
数据库驱动等
构建跳过跳过特定任务gradle build -x test
// 或在脚本中:test.enabled = false
快速构建,但不运行测试

注意事项:

  • 推荐使用 options.release 而非 sourceCompatibility 和 targetCompatibility(Java 9+)。
  • useJUnitPlatform() 是使用 JUnit 5 的必需配置。
  • maxParallelForks 应根据 CPU 核心数调整。
  • 避免在生产构建中跳过测试(-x test)。

9.4 生成 JAR 文件与 MANIFEST 配置

配置项说明代码示例注意事项
jar 任务生成 JAR 文件jar { // 配置 }默认任务,输出到 build/libs
MANIFEST.MFJAR 包内的元数据文件jar { manifest { attributes('Implementation-Title': project.name, 'Implementation-Version': project.version, 'Main-Class': 'com.example.Main') } }可用于指定主类
主类配置(可执行 JAR)指定程序入口点jar { manifest { attributes 'Main-Class': 'com.example.App' } }需配合类路径或 fat jar
添加文件到 JAR将额外文件打包jar { from 'README.txt'; from(sourceSets.main.output) { exclude '**/*.class' } }支持 from + exclude/include
文件重命名在 JAR 中重命名条目jar { rename '(.+).properties', 'config/$1.properties' }使用正则表达式
排除文件防止文件被打包jar { exclude 'META-INF/*.SF', 'META-INF/*.DSA' }如排除签名文件
多个 JAR生成不同用途的 JARtask sourcesJar(type: Jar) { archiveClassifier = 'sources'; from sourceSets.main.allSource }; artifacts { archives sourcesJar }发布源码 JAR
Javadoc JAR生成文档 JARtask javadocJar(type: Jar) { archiveClassifier = 'javadoc'; from javadoc }发布 Javadoc
定制 JAR 名称修改输出文件名jar { archiveBaseName = 'myapp'; archiveVersion = '1.0'; archiveExtension = 'jar' }或使用 archiveFileName
清单继承从其他清单合并属性jar { manifest { from 'src/config/MANIFEST.MF'; attributes 'Built-By': System.getProperty('user.name') } }支持多个 from

注意事项:

  • 仅配置 Main-Class 的 JAR 无法直接运行(缺少依赖)。
  • 要创建可运行的”fat jar”,需使用 shadow 插件或手动配置 jar 任务包含依赖。
  • archiveClassifier 用于区分不同类型的构件(如 sources, javadoc)。
  • MANIFEST 配置是发布库或应用的重要步骤。

9.5 运行 Java 应用(JavaExec)

配置项说明代码示例注意事项
JavaExec 任务执行 Java 应用程序task runApp(type: JavaExec) { mainClass = 'com.example.Main'; classpath = sourceSets.main.runtimeClasspath }核心方式
mainClass指定主类mainClass = 'com.example.Launcher'
// 或 main = 'com.example.Launcher'
必须设置
classpath设置类路径classpath = sourceSets.main.runtimeClasspath
// 或 classpath configurations.runtimeClasspath, sourceSets.main.output
包含编译输出和依赖
JVM 参数传递给 JVM 的参数jvmArgs = ['-Xmx512m', '-XX:+HeapDumpOnOutOfMemoryError']如内存、GC 选项
程序参数传递给主方法的参数args = ['arg1', 'arg2']String 列表
系统属性设置系统属性systemProperties = [ 'prop.name': 'value', 'debug': 'true' ]可在代码中通过 System.getProperty 读取
环境变量设置环境变量environment = [ 'ENV_VAR': 'prod' ]影响进程环境
标准输入/输出重定向流standardInput = new ByteArrayInputStream("input\n".bytes); standardOutput = new FileOutputStream('output.log')高级用法
应用 application 插件简化应用运行plugins { id 'application' }; mainClass = 'com.example.App' // 生成 run 任务推荐用于可执行应用
run 任务application 插件提供的快捷任务gradle run // 直接运行应用自动配置 classpath 和 mainClass
调试运行启用远程调试jvmArgs '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'便于 IDE 调试

注意事项:

  • JavaExec 是运行 Java 应用的底层任务,application 插件在此基础上提供更高层的 run 任务。
  • 必须正确设置 classpath,否则会报 ClassNotFoundException。
  • args 和 jvmArgs 区分清楚:args 传给 main(String[] args),jvmArgs 传给 JVM。
  • 使用 application 插件可以自动生成启动脚本(startScripts 任务)。

第十章:构建脚本优化与最佳实践

10.1 脚本模块化(apply from:)

方法说明代码示例注意事项
apply from:将公共配置提取到外部 .gradle 文件// common.gradle; group = 'com.example'; version = '1.0.0'
// build.gradle; apply from: 'common.gradle'
基础模块化方式
按功能拆分将不同配置分离到不同文件config.gradle:项目元数据
dependencies.gradle:依赖声明
publishing.gradle:发布配置
quality.gradle:代码质量任务
提升可维护性
子项目模块化在子项目中应用共享脚本// 子项目 build.gradle; apply from: '../gradle/java-conventions.gradle'实现跨项目一致性
参数化脚本通过扩展属性传递参数// script.gradle; ext.projectType = project.findProperty('projectType') ?: 'library'
// 应用时设置:project.ext.projectType = 'service'; apply from: 'config.gradle'
增强脚本灵活性
动态应用根据条件决定是否应用脚本if (project.hasProperty('enableMonitoring')) { apply from: 'monitoring.gradle' }实现可选功能
集中式脚本管理在 gradle/ 目录下组织脚本project/
├── gradle/
│ ├── conventions/
│ │ ├── java.gradle
│ │ └── test.gradle
│ └── scripts/
│ └── deploy.gradle
└── build.gradle
推荐项目结构
脚本作用域外部脚本与主脚本共享 Project 对象// in external.gradle; println "Applying to $project.name"上下文一致
避免循环引用不要出现脚本互相 apply-会导致构建失败
使用 buildSrc 模块化将复杂逻辑移到 buildSrc 的二进制插件// buildSrc 模块中开发插件; apply plugin: 'com.example.java-conventions'更强大,支持编译时检查
版本控制将模块化脚本纳入版本控制git add gradle/*.gradle团队共享配置

注意事项:

  • 模块化脚本是提升大型项目可维护性的关键。
  • 避免过度拆分,保持逻辑内聚。
  • 为外部脚本编写清晰的注释和文档。
  • apply from: 适用于项目内共享,跨项目复用推荐使用二进制插件。

10.2 使用 gradle.properties 管理属性

属性类型说明代码示例注意事项
项目级属性位于项目根目录,影响当前构建// gradle.properties; version=1.2.0; org.gradle.jvmargs=-Xmx2g最常用
用户级属性位于 ~/.gradle/gradle.properties,影响所有构建// ~/.gradle/gradle.properties; org.gradle.daemon=true; systemProp.http.proxyHost=proxy.company.com全局配置,如代理、守护进程
命令行传参使用 -P 传递属性gradle build -Pversion=2.0.0-SNAPSHOT优先级最高
访问属性在 build.gradle 中通过 project.property 或直接引用println project.version
println version // Groovy DSL 支持省略 project.
推荐使用 project.version
类型转换属性默认为 String,需手动转换ext.maxHeap = project.findProperty('maxHeap')?.toInteger() ?: 1024注意空值处理
敏感信息避免在 gradle.properties 中存储密码推荐使用环境变量或 ~/.gradle/gradle.properties安全考虑
构建性能属性配置 Gradle 运行时行为org.gradle.parallel=true; org.gradle.configureondemand=true; org.gradle.caching=true显著提升性能
JVM 参数设置 Gradle 守护进程的 JVM 选项org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8根据项目大小调整内存
仓库认证配置私有仓库凭据mavenRepoUsername=user; mavenRepoPassword=pass
// build.gradle 中:credentials { username mavenRepoUsername; password mavenRepoPassword }
分离配置与代码
环境特定属性为不同环境定义属性// gradle.properties; api.url.dev=http://localhost:8080; api.url.prod=https://api.example.com结合 Profile 使用

注意事项:

  • 项目级 gradle.properties 应提交到版本控制。
  • 用户级 ~/.gradle/gradle.properties 通常不提交,用于本地配置。
  • 属性优先级:命令行 -P > 项目级 > 用户级。
  • 使用 findProperty() 可安全处理可能不存在的属性。

10.3 构建缓存与性能优化

优化策略说明配置方式效果
Gradle 守护进程长生命周期的后台进程,避免 JVM 启动开销默认启用显著提升连续构建速度
并行构建并行执行独立的项目任务org.gradle.parallel=true(gradle.properties)多项目构建提速
配置缓存缓存构建脚本配置阶段的结果gradle build --configuration-cache
org.gradle.configuration-cache=true
大幅减少配置时间
构建缓存(Build Cache)缓存任务输出,避免重复执行org.gradle.caching=true
// 启用远程缓存:buildCache { remote(HttpBuildCache) { url = "https://cache.company.com"; push = true } }
CI/CD 和团队共享缓存
增量编译仅重新编译变更的文件Java 插件默认支持编译速度提升
增量注解处理支持增量的注解处理器使用支持增量的处理器(如 Dagger, Lombok)加快编译
按需配置仅配置执行的项目org.gradle.configureondemand=true多项目构建初始化更快
文件系统监视Gradle 7+ 监视文件变更默认启用(Windows/macOS/Linux)更快的 up-to-date 检查
减少插件应用仅在需要的项目应用插件subprojects { if (file('src/main/java').exists()) { apply plugin: 'java' } }缩短配置阶段
优化依赖声明使用 implementation 替代 apidependencies { implementation '...' // 而非 api }减少传递依赖,加快解析

注意事项:

  • 守护进程、并行、缓存是提升性能的三大支柱。
  • 配置缓存是较新功能,需确保插件兼容。
  • 远程构建缓存在 CI/CD 环境中效果最佳,可共享缓存。
  • 定期监控构建时间,识别瓶颈任务。
  • 避免在构建脚本中执行耗时的 I/O 操作。

10.4 日志输出与调试技巧

技巧说明代码/命令示例注意事项
日志级别控制输出详细程度gradle build --info
gradle build --debug
—debug 最详细
任务日志查看特定任务的执行gradle compileJava --info定位任务问题
静默模式减少输出gradle build -q仅输出错误
打印信息在脚本中输出调试信息println "Project: $name"
logger.quiet("Quiet message")
logger.info("Info: $value")
logger.debug("Debug detail")
使用 logger 推荐
断点调试在 IDE 中调试构建脚本1. 在 build.gradle 中设断点
2. 使用 —no-daemon
3. 在 IDE 中远程调试 5005 端口
需关闭守护进程
查看依赖树分析依赖关系gradle dependencies
gradle :web:dependencies --configuration runtimeClasspath
诊断版本冲突
查看任务依赖分析任务执行顺序gradle build --dry-run
gradle taskName --task-graph
预览执行计划
检查任务状态查看任务是否 up-to-dategradle build --info输出 UP-TO-DATE 或 FROM-CACHE
脚本执行顺序理解初始化、配置、执行阶段// 阶段钩子:settings.gradle: println "In settings"; build.gradle: println "In configuration"; task myTask { doFirst { println "In execution" } }避免在配置阶段执行
使用 buildScan()生成构建扫描报告plugins { id 'com.gradle.build-scan' version '3.16' }; buildScan { termsOfServiceUrl = 'https://gradle.com/terms-of-service'; termsOfServiceAgree = 'yes' }; gradle build --scan获取详细分析

注意事项:

  • 使用 logger.* 方法比 println 更规范,可控制级别。
  • —debug 输出非常详细,通常先用 —info。
  • 调试脚本时务必使用 —no-daemon 以避免守护进程影响。
  • build —dry-run 是分析构建流程的好工具。

10.5 构建扫描(Build Scan)

功能说明使用方式价值
构建扫描概念将构建的详细数据上传到服务进行分析gradle build --scan深入洞察构建性能
免费服务Gradle 官方提供的 buildScan.com—scan 参数自动上传快速获取报告
企业版Gradle Enterprise,私有部署配置企业服务器 URL安全、可审计
性能分析识别耗时最长的任务报告中 “Performance” 标签页优化构建瓶颈
依赖分析可视化依赖树和冲突”Dependencies” 标签页解决版本问题
缓存效率查看本地/远程缓存命中率”Build Cache” 标签页评估缓存策略
任务详情查看每个任务的输入、输出、执行时间点击具体任务深入诊断
环境信息查看 Gradle 版本、JVM、OS 等”Environment” 标签页排查环境问题
比较构建对比两次构建的差异在网站上选择两个扫描进行比较评估优化效果
故障诊断快速定位构建失败原因失败任务高亮显示,堆栈跟踪加速调试
分享报告生成可分享的 URL上传后获得链接,可发给团队成员协作分析

注意事项:

  • —scan 会上传构建数据,敏感项目需确认合规性。
  • 企业环境中推荐使用 Gradle Enterprise。
  • 构建扫描是性能优化和故障排查的终极工具。
  • 可在 gradle.properties 中配置 gradle.enterprise.host 使用私有实例。
  • 免费版扫描数据保留有限时间,重要分析建议下载或使用企业版。

第十一章:Gradle 工具链与集成

11.1 与 IntelliJ IDEA 集成

集成方式说明操作步骤/配置注意事项
直接导入IDEA 原生支持 Gradle 项目1. 打开 IDEA
2. 选择 “Open” 或 “Import Project”
3. 选择 build.gradle 文件
4. 选择 “Import project from external model” → Gradle
5. 配置 JDK 和 Gradle 版本
推荐方式,自动同步
Gradle 工具窗口管理 Gradle 任务和项目View → Tool Windows → Gradle可浏览、运行任务,刷新项目
自动导入修改 build.gradle 后自动同步Settings → Build → Build Tools → Gradle → 勾选 “Auto-import”提高开发效率,但可能影响性能
使用 Gradle 构建让 IDEA 使用 Gradle 而非内置构建器Settings → Build → Build Tools → Gradle → “Build and run using: Gradle”保证本地构建与 CI 一致性
JVM 选项配置设置 IDEA 内 Gradle 进程的 JVM 参数Help → Edit Custom VM Options…
添加 -Dorg.gradle.jvmargs=-Xmx2g
解决内存不足问题
多版本 Gradle 支持在同一机器使用不同 Gradle 版本在导入时选择 “Use Gradle from” → “Specified location” 或使用 Wrapper避免版本冲突
调试构建脚本在 IDEA 中调试 build.gradle1. 在 build.gradle 中设断点
2. 右键任务 → “Debug ‘taskName‘“
3. 确保 —no-daemon
需关闭守护进程才能调试
Kotlin DSL 支持编辑 build.gradle.ktsIDEA 提供语法高亮、代码补全、错误检查功能完善,推荐使用
忽略 generated 目录防止 IDE 索引生成的代码IDEA 自动识别 build/ 目录为 excluded若未识别,手动标记
项目 SDK 配置设置项目使用的 JDKFile → Project Structure → Project → Project SDK确保与 build.gradle 中 sourceCompatibility 一致

注意事项:

  • 始终使用 Gradle Wrapper 导入项目,确保团队环境一致。
  • 若遇到同步问题,尝试点击 Gradle 工具栏的 “Reload All Gradle Projects”。
  • 对于大型项目,关闭 “Auto-import” 并手动刷新以提高响应速度。
  • 推荐将 “Build and run using” 设置为 Gradle,避免构建差异。

11.2 与 Android 构建系统(AGP)关系

概念说明配置示例注意事项
AGP 本质Android Gradle Plugin,一个基于 Gradle 的二进制插件plugins { id 'com.android.application' }核心是 Gradle 插件
构建生命周期继承并扩展 Gradle 生命周期android {...} DSL 扩展了 Project在 Gradle 的基础上添加 Android 任务
新增任务AGP 添加大量 Android 特定任务assembleDebug, assembleRelease, installDebug, lint, connectedAndroidTest可通过 gradle tasks 查看
新增 DSLandroid {} 块提供 Android 配置android { compileSdk 34; defaultConfig { applicationId "com.example.app"; minSdk 21; targetSdk 34; versionCode 1; versionName "1.0" }; buildTypes { release { minifyEnabled true } } }替代旧版 build.gradle 结构
源集扩展支持 productFlavors 和 buildTypes 源集android { flavorDimensions "version"; productFlavors { free { dimension "version" }; paid { dimension "version" } } }实现多渠道构建
依赖管理复用 Gradle 的 dependencies DSLdependencies { implementation 'androidx.appcompat:appcompat:1.6.1'; testImplementation 'junit:junit:4.13.2' }支持 implementation, api 等
构建变体(Build Variants)组合 buildType 和 productFlavor 生成 APK/AABdebug, release, freeDebug, paidRelease每个变体有独立的任务
R8/ProGuard代码混淆和缩减buildTypes { release { minifyEnabled true; shrinkResources true } }默认启用 R8
DEX 处理将字节码转换为 Android 可执行格式AGP 自动处理,无需手动配置支持 multidex
与 Gradle 版本对应AGP 版本需匹配特定 Gradle 版本查阅官方兼容性表不匹配会导致构建失败

注意事项:

  • AGP 是 Gradle 的超集,掌握 Gradle 是理解 Android 构建的基础。
  • 升级 AGP 时必须同时升级 Gradle Wrapper 到兼容版本。
  • android {} DSL 是 AGP 的核心配置入口。
  • Android Studio 内置的 Gradle 版本应与项目 wrapper 保持一致。

11.3 与 CI/CD 集成(Jenkins, GitHub Actions)

CI/CD 平台集成要点示例配置片段注意事项
通用原则使用 Wrapper 确保环境一致性./gradlew build避免使用全局 gradle 命令
Jenkins使用 Pipeline 或 Freestyle 项目// Jenkinsfile; pipeline { agent any; stages { stage('Build') { steps { sh './gradlew build --no-daemon' } }; stage('Test') { steps { sh './gradlew test --continue' } } } }—no-daemon 避免守护进程残留
GitHub Actions使用 actions/setup-java 和 gradle/wrapper-validationname: CI; on: [push, pull_request]; jobs: build: runs-on: ubuntu-latest; steps: - uses: actions/checkout@v4; - uses: actions/setup-java@v4 with: java-version: '17'; distribution: 'temurin'; - uses: gradle/wrapper-validation-action@v1; - uses: gradle/gradle-build-action@v2 with: arguments: build --no-daemon官方 action 简化配置
缓存优化缓存 Gradle 依赖和构建缓存- uses: actions/cache@v3 with: path: ~/.gradle/caches; key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}显著减少 CI 时间
并行执行在多核机器上并行构建./gradlew build --parallel多项目构建提速
持续反馈上传测试报告和代码覆盖率使用 jacocoReport 任务,发布到 SonarQube 或 Codecov实现质量门禁
发布工件构建后发布 JAR/APK./gradlew publishToMavenLocal 或部署到 Nexus/Artifactory需配置凭据
环境变量从 CI 环境注入敏感信息./gradlew build -PsonatypeUsername=$SONATYPE_USER -PsonatypePassword=$SONATYPE_PASS避免硬编码密码
构建扫描生成构建分析报告./gradlew build --scan需同意服务条款
状态检查将构建结果反馈给 Git所有平台均支持PR 的必过检查项

注意事项:

  • 始终在 CI 中使用 ./gradlew,而非假设系统已安装 Gradle。
  • 启用构建缓存(org.gradle.caching=true)并在 CI 中持久化 ~/.gradle/caches 目录。
  • 使用 —no-daemon 防止守护进程占用资源。
  • —continue 允许在部分测试失败时继续执行其他任务,获取完整报告。

11.4 Gradle Wrapper 使用与配置

项目说明配置方式/命令注意事项
Wrapper 概念包装脚本(gradlew)和 JAR,用于引导特定版本的 Gradle自动生成的文件:gradlew, gradlew.bat, gradle/wrapper/gradle-wrapper.jar, gradle/wrapper/gradle-wrapper.properties核心是 gradle-wrapper.jar
初始化 Wrapper为项目创建 Wrappergradle wrapper --gradle-version 8.5首次使用时运行
配置属性文件gradle/wrapper/gradle-wrapper.propertiesdistributionBase=GRADLE_USER_HOME; distributionPath=wrapper/dists; zipStoreBase=GRADLE_USER_HOME; zipStorePath=wrapper/dists; distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zipdistributionUrl 决定 Gradle 版本
分发类型bin(仅 Gradle)vs all(含源码和文档)修改 distributionUrl 中的 -bin 或 -all通常使用 -bin
升级 Gradle 版本修改 distributionUrl手动编辑 properties 文件或重新运行 gradle wrapper --gradle-version X.Y团队需同步更新
使用 Wrapper开发者和 CI 使用 ./gradlew./gradlew build
./gradlew tasks
确保可执行权限(chmod +x gradlew)
Wrapper 脚本跨平台启动脚本gradlew(Unix), gradlew.bat(Windows)无需安装 Gradle
安全性验证 Wrapper JAR 完整性gradle wrapper --gradle-distribution-sha256-sum=<hash>防止中间人攻击
自定义分发源使用私有仓库下载 Gradle修改 distributionUrl 为内部 URLhttp://repo.internal/gradle-8.5-bin.zip
Wrapper 任务更新 Wrapper 自身gradle wrapper --gradle-version 8.6会更新所有相关文件
最佳实践将 Wrapper 文件提交到版本控制git add gradlew gradlew.bat gradle/确保团队一致性

注意事项:

  • Wrapper 是现代 Gradle 项目的标准,不应要求用户手动安装 Gradle。
  • 提交 gradle-wrapper.jar 和 gradle-wrapper.properties 到 Git。
  • 升级 Gradle 版本时,务必更新 gradle-wrapper.properties 并通知团队。
  • 在 CI/CD 中,优先使用 ./gradlew 命令。