5月27日 23:20

Gradle 中的 Task 是什么?如何创建和配置 Task?

核心答案

Task 是 Gradle 构建的最小执行单元,代表一个原子操作(编译、打包、测试等)。每个 Task 包含名称、类型、动作(Action)、依赖关系和输入/输出。创建 Task 有三种方式,推荐使用 tasks.register() 实现延迟初始化,避免配置阶段不必要的开销。

创建 Task

register vs create vs task 关键字

groovy
// 推荐:延迟创建,仅在实际需要时实例化 tasks.register('myTask') { doLast { println 'Executing myTask' } } // 立即创建,配置阶段就会实例化 tasks.create('myTask') { doLast { println 'Executing myTask' } } // DSL 快捷方式,等同 create task myTask { doLast { println 'Executing myTask' } }

registercreate 的核心区别在于:register 返回 TaskProvider,Task 实例在首次被引用时才创建。大型项目中大量使用 create 会导致配置阶段耗时增加,register 可显著改善构建性能。

指定 Task 类型

groovy
tasks.register('copyFiles', Copy) { from 'src/main/resources' into 'build/resources' }

继承内置类型(Copy、Delete、Exec 等)可以复用已有的文件操作逻辑,不必从零实现。

配置 Task

groovy
tasks.register('myTask') { group = 'Custom Tasks' // Gradle 面板中的分组 description = '自定义任务描述' // gradle tasks 时的说明 dependsOn 'clean', 'compileJava' // 依赖其他任务 mustRunAfter 'test' // 硬排序约束 shouldRunAfter 'build' // 软排序约束(可被 Gradle 忽略) inputs.file('config.properties') // 声明输入 outputs.dir('build/output') // 声明输出 doFirst { println '执行前' } doLast { println '执行后' } }

声明 inputs/outputs 的意义在于启用增量构建:Gradle 检测到输入输出未变化时会跳过 Task 执行,这是提升构建速度的关键机制。

依赖与排序

  • dependsOn:声明必须先完成的依赖,Gradle 据此构建有向无环图(DAG)决定执行顺序
  • mustRunAfter:硬约束,两个任务同时被调度时保证先后顺序,但不引入依赖
  • shouldRunAfter:软约束,Gradle 在并行执行优化时可以忽略
  • finalizedBy:无论当前任务成功或失败,都会执行收尾任务(如资源清理)
groovy
tasks.register('taskA') { finalizedBy 'cleanup' doLast { println 'Task A' } } tasks.register('cleanup') { doLast { println 'Cleanup' } }

执行控制

groovy
// 条件执行 tasks.register('conditionalTask') { onlyIf { project.hasProperty('runConditional') } doLast { println '条件满足才执行' } } // 禁用任务 tasks.register('disabledTask') { enabled = false } // 抛出 StopExecutionException 跳过当前动作 doFirst { if (!project.hasProperty('force')) { throw new StopExecutionException() } }

追问

register 创建的 Task 如何在其他地方引用? 使用 tasks.named('myTask') 获取 TaskProvider,再通过 .configure { } 追加配置。不要对 register 的 Task 直接用 tasks.myTask,那会触发立即实例化,失去延迟初始化的优势。

mustRunAfter 和 dependsOn 有什么区别? dependsOn 会建立真正的依赖关系,被依赖的任务一定会执行;mustRunAfter 只是排序约束,仅当两个任务都在本次构建的执行计划中时才生效,不会把对方拉入执行图。

为什么不要在 Task 体中直接写逻辑而要用 doFirst/doLast? Task 闭包中的代码在配置阶段执行,而 doFirst/doLast 中的代码在执行阶段执行。配置阶段写逻辑会导致每次运行任何 Task 都会执行这些代码,产生副作用和性能浪费。

标签:Gradle