Appearance
构建生命周期
理解 Gradle 的构建生命周期对于编写正确的构建脚本至关重要,特别是区分配置阶段和执行阶段。
三个阶段
┌─────────────────────────────────────────────────────┐
│ 阶段一:初始化(Initialization) │
│ • 读取 settings.gradle.kts │
│ • 确定参与构建的项目 │
│ • 创建 Project 对象 │
└─────────────────────┬───────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 阶段二:配置(Configuration) │
│ • 执行所有 build.gradle.kts 中的配置代码 │
│ • 注册所有 Task │
│ • 构建 Task 依赖图(DAG) │
└─────────────────────┬───────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 阶段三:执行(Execution) │
│ • 按依赖顺序执行被选中的 Task │
│ • 每个 Task 先检查增量构建 │
│ • 执行 Task 的 doFirst/doLast 动作 │
└─────────────────────────────────────────────────────┘详细演示
创建一个演示三个阶段的构建脚本:
kotlin
// settings.gradle.kts
println("【初始化阶段】解析 settings.gradle.kts")
rootProject.name = "lifecycle-demo"kotlin
// build.gradle.kts
println("【配置阶段】开始执行 build.gradle.kts")
tasks.register("taskA") {
println("【配置阶段】注册 taskA")
doFirst {
println("【执行阶段】taskA doFirst")
}
doLast {
println("【执行阶段】taskA doLast")
}
}
tasks.register("taskB") {
println("【配置阶段】注册 taskB")
dependsOn("taskA")
doLast {
println("【执行阶段】taskB doLast")
}
}
println("【配置阶段】build.gradle.kts 执行完毕")运行 ./gradlew taskB 的输出:
【初始化阶段】解析 settings.gradle.kts
【配置阶段】开始执行 build.gradle.kts
【配置阶段】注册 taskA
【配置阶段】注册 taskB
【配置阶段】build.gradle.kts 执行完毕
> Task :taskA
【执行阶段】taskA doFirst
【执行阶段】taskA doLast
> Task :taskB
【执行阶段】taskB doLast
BUILD SUCCESSFUL in 0s配置阶段的注意事项
重要:配置阶段的代码每次运行任意任务都会执行,即使你只运行 ./gradlew help。
常见错误:在配置阶段做耗时操作
kotlin
// ❌ 错误写法:配置阶段调用 API(每次构建都执行)
tasks.register("deploy") {
val version = fetchVersionFromServer() // 网络调用!每次都执行
doLast {
deployApp(version)
}
}
// ✅ 正确写法:在执行阶段做耗时操作
tasks.register("deploy") {
doLast {
val version = fetchVersionFromServer() // 只在 deploy 任务执行时调用
deployApp(version)
}
}使用懒加载避免配置阶段问题
kotlin
// ✅ 推荐:使用 Provider API 懒加载
tasks.register("printVersion") {
val versionProvider = providers.gradleProperty("version")
doLast {
println("Version: ${versionProvider.get()}")
}
}生命周期钩子
Gradle 提供了在各阶段关键时间点执行代码的钩子。
项目配置完成钩子
kotlin
// 根项目 build.gradle.kts
gradle.afterProject { project ->
println("项目 ${project.name} 配置完成")
}
gradle.projectsEvaluated {
println("所有项目配置完成,即将构建 Task DAG")
}Task 执行钩子
kotlin
gradle.taskGraph.whenReady { graph ->
println("Task DAG 构建完成")
println("将执行 ${graph.allTasks.size} 个任务")
if (graph.hasTask(":publish")) {
println("注意:将发布到远程仓库!")
}
}
gradle.taskGraph.beforeTask { task ->
println("即将执行任务:${task.path}")
}
gradle.taskGraph.afterTask { task, state ->
if (state.failure != null) {
println("任务失败:${task.path}")
}
}构建完成钩子
kotlin
gradle.buildFinished { result ->
if (result.failure != null) {
println("构建失败:${result.failure?.message}")
} else {
println("构建成功!")
}
}Task 的生命周期
每个 Task 本身也有自己的生命周期:
Task 注册(配置阶段)
↓
Task 配置(配置阶段,执行 task {} 块中的配置代码)
↓
Task 依赖解析(执行阶段开始前)
↓
Task 输入/输出检查(增量构建判断)
↓ 需要执行
doFirst 动作列表(按添加顺序)
↓
Task 主体动作
↓
doLast 动作列表(按添加顺序)kotlin
tasks.register("myTask") {
// 配置阶段执行的代码
val message = "Hello"
doFirst {
println("最先执行:$message")
}
doFirst {
println("doFirst 按倒序执行(后加的先执行)")
}
doLast {
println("doLast 按正序执行(先加的先执行)")
}
doLast {
println("最后执行")
}
}执行结果:
doFirst 按倒序执行(后加的先执行)
最先执行:Hello
doLast 按正序执行(先加的先执行)
最后执行与 Maven 生命周期对比
| Maven 生命周期 | 最接近的 Gradle 任务 |
|---|---|
validate | - |
compile | compileJava |
test | test |
package | jar / war |
verify | check |
install | publishToMavenLocal |
deploy | publish |
Maven 生命周期是固定的,Gradle 的任务依赖图是动态构建的,更灵活。