Gradle 核心概念
kotlin // Kotlin DSL 示例 plugins { // 插件块 java application }
repositories { // 仓库配置 mavenCentral() }
dependencies { // 依赖配置 implementation("com.google.guava:guava:31.1-jre") }
application { // 插件提供的扩展配置 mainClass.set("com.example.Main") }
## 2. 任务(Task)—— 构建的基本工作单元
### 2.1 什么是任务
**任务**是 Gradle 中的原子工作单元,代表一次具体的操作,例如编译源代码、运行测试、打包 JAR 文件等。一个项目的整个构建过程由一系列有序执行的任务组成。
### 2.2 内置任务与自定义任务
插件通常会带来大量内置任务,你可以在命令行通过 `gradle tasks` 查看所有可用任务。你也可以轻松定义自己的任务:
```kotlin
tasks.register("hello") { // 注册一个新任务
doLast {
println("Hello, Gradle!")
}
}
任务之间可以显式声明依赖关系,确定执行顺序:
val compile = tasks.named("compileJava")
tasks.register("myCustomTask") {
dependsOn(compile) // 只有 compileJava 执行完后才执行本任务
doLast { ... }
}
2.3 任务生命周期钩子
每个任务都提供 doFirst 和 doLast 闭包/代码块,用于在任务动作列表的首尾插入行为。这些钩子使得在不修改原有任务的情况下注入额外逻辑成为可能。
3. 构建生命周期
Gradle 执行构建时会经历三个固定的阶段:
-
初始化(Initialization)
- 检测
settings.gradle(.kts)文件,确定参与本次构建的所有项目(Project)。 - 为每个项目创建一个
Project实例(多项目时为层次结构)。
- 检测
-
配置(Configuration)
- 按顺序执行每个项目的构建脚本,配置项目对象。
- 任务对象被创建和配置,但不会执行任何任务动作。
- 整个依赖关系图在配置阶段末尾确定。
-
执行(Execution)
- 运行用户在命令行中指定的任务(或默认任务),按依赖关系顺序执行。
- 真正发生编译、测试等实际工作。
区分配置和执行是 Gradle 新手最容易出错的地方。任务配置代码在配置阶段就运行,而 doFirst/doLast 中的动作代码只在执行阶段运行。因此,避免在任务配置时执行重操作。
4. 插件(Plugin)—— 可复用能力的封装
插件是 Gradle 扩展机制的核心。每个插件都会为项目添加:
- 新任务(如
classes、test) - 域对象(如 SourceSet)
- 约定默认值(如目录布局)
- 新的 DSL 扩展(如
application{ })
最常用的官方插件:
| 插件标识符 | 主要功能 |
|---|---|
java |
添加 Java 编译、测试、打包能力 |
application |
支持可运行的 JVM 应用及 run 任务 |
java-library |
在 java 基础上增加 api 依赖配置 |
maven-publish |
发布构件到 Maven 仓库 |
应用插件只需在构建脚本的 plugins 块中声明:
plugins {
id("java")
id("org.springframework.boot") version "3.0.5"
}
5. 依赖管理
Gradle 采用 变体感知 的依赖管理模型,通过配置(Configuration)来控制依赖的范围和用途。
5.1 常用依赖配置
implementation:依赖只在本模块内部使用,不会传递泄露给消费者(编译和运行时可见)。api:依赖会泄露给消费者编译路径,适用于库模块(需java-library插件)。runtimeOnly:仅在运行时需要,不参与编译。testImplementation/testRuntimeOnly:仅用于测试源码。
5.2 声明仓库与依赖
repositories {
mavenCentral()
google()
}
dependencies {
implementation("org.apache.commons:commons-lang3:3.12.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
Gradle 会将声明的依赖从仓库下载到本地缓存,并在配置阶段构建依赖解析图。动态版本(如 1.+)和递增版本号的使用需谨慎,它们会影响构建的可复现性。
6. 多项目构建与 Settings 文件
任何 Gradle 构建的根目录都必须包含 settings.gradle(.kts) 文件,它用于定义项目名称和包含的子项目:
rootProject.name = "my-app"
include("core", "app")
子项目之间可以通过项目路径互相引用依赖:
// app/build.gradle.kts
dependencies {
implementation(project(":core"))
}
Gradle 会根据 settings 文件形成项目树,在配置阶段遍历所有子项目,从而实现集中管理与跨项目任务调用。
7. 增量构建与缓存
Gradle 通过增量构建大幅提升效率:
- 输入/输出快照:任务声明其输入和输出属性,Gradle 在连续执行时对比它们。若输入和输出自上次运行后均无变化,任务被标记为
UP-TO-DATE并跳过。 - 构建缓存:本地和远程缓存可以存储任务输出,使得不同机器或分支间复用,极大加速 CI/CD 构建。
要使任务支持增量,应显式注释输入输出文件/属性,例如:
abstract class MyTask : DefaultTask() {
@get:InputFile
abstract val sourceFile: RegularFileProperty
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun process() { ... }
}