Skip to content

构建生命周期与监控

源:Gradle 官方文档 - Build Lifecycle

深入理解 Gradle 构建生命周期,实现构建监控、性能分析和自动化任务插入。

Gradle 生命周期

三个阶段

Gradle 构建的三个阶段

1. Initialization(初始化)

2. Configuration(配置)

3. Execution(执行)

初始化阶段

作用:确定哪些项目参与构建。

主要文件settings.gradle.kts

kotlin
// settings.gradle.kts
rootProject.name = "MyApp"

include(":app")
include(":core")
include(":feature-login")

执行内容

  • 读取 settings.gradle.kts
  • 创建 Settings 对象
  • 确定项目结构
  • 创建 Project 对象

配置阶段

作用:配置所有项目,构建任务依赖图。

主要文件build.gradle.kts

kotlin
// build.gradle.kts
plugins {
    id("com.android.application")
}

android {
    compileSdk = 34  // 配置阶段执行
}

tasks.register("myTask") {
    println("配置阶段执行")  // 立即执行
    
    doLast {
        println("执行阶段执行")  // 稍后执行
    }
}

执行内容

  • 读取所有 build.gradle.kts
  • 执行配置代码
  • 创建任务对象
  • 建立任务依赖关系

执行阶段

作用:执行选定的任务。

bash
./gradlew assembleDebug  # 仅执行 assembleDebug 及其依赖

执行内容

  • 按依赖顺序执行任务
  • 执行 doFirstdoLast 等 action
  • 生成构建产物

生命周期钩子

Settings 钩子

settings.gradle.kts

kotlin
gradle.beforeSettings {
    println("在 settings 被解析前")
}

gradle.settingsEvaluated {
    println("settings 解析完成")
}

gradle.projectsLoaded {
    println("所有项目已加载")
}

Project 钩子

build.gradle.kts

kotlin
// 项目评估前
beforeEvaluate {
    println("项目评估前")
}

// 项目评估后
afterEvaluate {
    println("项目评估后")
    println("所有任务已创建")
}

任务图钩子

kotlin
gradle.taskGraph.whenReady {
    println("任务图已就绪")
    println("将要执行的任务:${allTasks.map { it.name }}")
}

gradle.taskGraph.beforeTask { task ->
    println("任务 ${task.name} 开始执行")
}

gradle.taskGraph.afterTask { task, state ->
    if (state.failure != null) {
        println("任务 ${task.name} 失败")
    } else {
        println("任务 ${task.name} 完成")
    }
}

Build Service 钩子

kotlin
abstract class TimingService : BuildService<BuildServiceParameters.None> {
    private val taskTimes = mutableMapOf<String, Long>()
    
    fun startTask(taskName: String) {
        taskTimes[taskName] = System.currentTimeMillis()
    }
    
    fun endTask(taskName: String) {
        val start = taskTimes[taskName] ?: return
        val duration = System.currentTimeMillis() - start
        println("任务 $taskName 耗时: ${duration}ms")
    }
}

实战:构建耗时统计

简单统计

kotlin
// build.gradle.kts
val taskTimes = mutableMapOf<String, Long>()

gradle.taskGraph.beforeTask { task ->
    taskTimes[task.path] = System.currentTimeMillis()
}

gradle.taskGraph.afterTask { task, state ->
    val start = taskTimes[task.path] ?: return@afterTask
    val duration = System.currentTimeMillis() - start
    println("${task.path}: ${duration}ms")
}

gradle.buildFinished {
    println("\n=== 构建统计 ===")
    taskTimes.entries
        .sortedByDescending { it.value }
        .take(10)
        .forEach { (task, time) ->
            println("$task: ${time}ms")
        }
}

Build Service 统计

kotlin
abstract class BuildTimingService : BuildService<BuildServiceParameters.None>,
    OperationCompletionListener {
    
    private val timings = ConcurrentHashMap<String, Long>()
    
    override fun onFinish(event: FinishEvent) {
        val descriptor = event.descriptor
        val result = event.result
        
        if (descriptor is TaskDescriptor) {
            val duration = result.endTime - result.startTime
            timings[descriptor.taskPath] = duration
        }
    }
    
    fun printReport() {
        println("\n=== 构建耗时报告 ===")
        timings.entries
            .sortedByDescending { it.value }
            .forEach { (task, duration) ->
                println("$task: ${duration}ms")
            }
    }
}

// 注册服务
val timingService = gradle.sharedServices.registerIfAbsent(
    "buildTiming",
    BuildTimingService::class.java
) {}

// 监听完成事件
gradle.buildFinished {
    timingService.get().printReport()
}

实战:自动任务插入

在特定任务前执行

kotlin
tasks.register("checkEnvironment") {
    doLast {
        println("检查构建环境...")
        // 检查 JDK 版本、环境变量等
    }
}

gradle.taskGraph.whenReady {
    if (hasTask(":app:assembleRelease")) {
        tasks.named("assembleRelease") {
            dependsOn("checkEnvironment")
        }
    }
}

动态添加任务依赖

kotlin
gradle.taskGraph.whenReady {
    allTasks.forEach { task ->
        if (task.name.contains("Release")) {
            // 所有 Release 任务前检查
            task.dependsOn("checkEnvironment")
        }
    }
}

实战:条件化构建

基于参数跳过任务

kotlin
tasks.register("expensiveTask") {
    onlyIf {
        project.hasProperty("runExpensive")
    }
    
    doLast {
        println("执行耗时任务")
    }
}

使用

bash
./gradlew build -PrunExpensive  # 执行
./gradlew build                  # 跳过

基于环境变量

kotlin
tasks.withType<Test>().configureEach {
    onlyIf {
        System.getenv("SKIP_TESTS") != "true"
    }
}

构建失败处理

捕获构建失败

kotlin
gradle.buildFinished { result ->
    if (result.failure != null) {
        println("构建失败:${result.failure?.message}")
        
        // 发送通知
        sendSlackNotification("构建失败")
    } else {
        println("构建成功")
    }
}

任务失败处理

kotlin
tasks.register("importantTask") {
    doLast {
        try {
            // 任务逻辑
        } catch (e: Exception) {
            // 记录日志
            logger.error("任务失败", e)
            
            // 清理资源
            cleanup()
            
            throw e
        }
    }
}

性能监控

配置阶段监控

kotlin
val configStartTime = System.currentTimeMillis()

gradle.projectsEvaluated {
    val configDuration = System.currentTimeMillis() - configStartTime
    println("配置阶段耗时: ${configDuration}ms")
    
    if (configDuration > 5000) {
        logger.warn("配置阶段过慢,建议优化")
    }
}

任务执行监控

kotlin
abstract class PerformanceMonitor : BuildService<BuildServiceParameters.None> {
    fun checkPerformance(taskName: String, duration: Long) {
        when {
            duration > 60000 -> logger.error("$taskName 超过1分钟")
            duration > 30000 -> logger.warn("$taskName 超过30秒")
        }
    }
}

最佳实践

避免在配置阶段执行耗时操作

kotlin
// ❌ 错误
val gitCommit = "git rev-parse HEAD".execute()  // 配置阶段执行

// ✅ 正确
val gitCommit = providers.exec {
    commandLine("git", "rev-parse", "HEAD")
}.standardOutput.asText  // 延迟执行

使用 Provider API

kotlin
// ❌ 立即求值
val version = getVersionFromGit()

// ✅ 延迟求值
val version = providers.provider { getVersionFromGit() }

减少 afterEvaluate 使用

kotlin
// ❌ 破坏配置缓存
afterEvaluate {
    tasks.named("compile") { ... }
}

// ✅ 使用插件钩子
pluginManager.withPlugin("java") {
    tasks.named("compile") { ... }
}

统一错误处理

kotlin
gradle.taskGraph.afterTask { task, state ->
    if (state.failure != null) {
        // 统一记录失败
        logTaskFailure(task, state.failure)
    }
}

避免全局配置

kotlin
// ❌ 影响所有项目
allprojects { ... }

// ✅ 使用约定插件
plugins {
    id("my.convention")
}