构建生命周期与监控
源: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 及其依赖执行内容:
- 按依赖顺序执行任务
- 执行
doFirst、doLast等 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")
}