Skip to content

构建生命周期

理解 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-
compilecompileJava
testtest
packagejar / war
verifycheck
installpublishToMavenLocal
deploypublish

Maven 生命周期是固定的,Gradle 的任务依赖图是动态构建的,更灵活。

下一步