【Deprecated】Gradle | 进阶篇(Project & Task & 构建生命周期)

简介: 【Deprecated】Gradle | 进阶篇(Project & Task & 构建生命周期)

目录

image.png


1. 前置知识


在 Gradle 中,build.gradle 脚本文件中每个元素都会映射一个 Java 类。其中最重要的两个类是 「Project」&「Task」。在这篇文章里,我将带你分析 Gradle 中 Project 与 Task 的原理与使用,以及分析 Gradle 构建的生命周期


这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~


2. Project 项目


Project 代表一个构建组件,在「构建-初始化阶段」,Gradle 引擎会为每个 build.gradle 脚本文件实例化一个 Project 实例。 所以我们在 build.gradle 中编写的构建逻辑,本质上相当于编写在 Project 类内部。


org.gradle.api.Project.java


public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
}
复制代码


Editting...


3. Task 任务


一个 Project 由一个或多个 Task 组成,Task 代表一个可执行的任务

org.gradle.api.Task.java


public interface Task extends Comparable<Task>, ExtensionAware
}
复制代码


3.1 定义 Task


定义 Task 的语法主要有三种:

  • 使用 task 函数:


task('hello')
task('world') {
}
复制代码
  • 使用 DSL 语言:


task(hello)
task(world) {
}
复制代码
  • 使用 tasks container:


tasks.create('hello')
tasks.create('world') {
}
复制代码


3.2 Task 属性


定义 Task 之后,就可以设置属性,设置属性的语法主要有两种:

  • 在创建 Task 时设置:


task hello(group : 'MyTask')
复制代码
  • 调用 setter 设置:


task hello {
    setGroup('MyTask')
}
复制代码


访问属性可以使用$符号或者 getter 方法,例如:


task hello(group : 'MyTask') {
    println "$group"
    println getGroup()
}
复制代码


Task 中比较常用的属性有:


属性 描述
name Task 标识符,在定义 Task 时指定
group Task 所属的组
description Task 的描述信息
type Task类型,默认为 DefaultTask(见 第 3.7 节
actions 动作列表(见 第 3.3 节
dependsOn 依赖 Task 集合


Task 最重要的三个概念是「Task 动作」&「Task 依赖」&「Task 配置」:


3.3 Task 动作


动作(action)就是 Task 中的构建逻辑,这些构建逻辑在「构建-执行阶段」运行。Task 接口提供了两个方法来声明 Task 任务:


动作 描述
doFirst(Closure) 表示 Task 的第一个动作
doLast(Closure) 表示 Task 的最后一个动作


例如:


task helloworld {
    doFirst {
        println "hello"
    }
    doLast {
        println "world"
    }
}
复制代码


除此之外,还可以在 Task 闭包外部添加动作:


task helloworld
helloworld.doFirst { println "hello" }
helloworld.doLast { println "world" }
复制代码


3.4 Task 输入 / 输出


3.5 Task 依赖


Task 往往不是独立存在的,而是与其他 Task 存在依赖关系,使用 dependsOn 方法来声明依赖一个或多个 Task ,例如:


task first {
    doFirst { println "first" }
}
task second {
    doFirst { println "second" }
}
task third {
    doFirst { println "third" }
}
// 单依赖
third.dependsOn first
// 多依赖
third.dependsOn([first,second])
复制代码


3.6 Task 配置


不在 Task 动作中定义的代码属于 Task 配置,两者完全不同:Task 配置运行在「构建-配置阶段」,Task 动作运行在「构建-执行阶段」,配置代码永远在动作代码之前执行。


3.7 自定义 Task


3.8 Task 类型


4. 理解 Gradle 构建生命周期


无论什么时候执行 Gradle 构建,都会先后执行三个生命周期阶段 ——「初始化」&「配置」&「执行」


4.1 初始化阶段(Initiliazation phase)


在初始化阶段,Gradle 会解析工程根目录下的setting.gradle文件,并构造一个 Settings 实例。Settings 是一个接口,主要包含以下方法:


org.gradle.api.initialization.Settings.Java


public interface Settings extends PluginAware, ExtensionAware {
    String DEFAULT_SETTINGS_FILE = "settings.gradle";
    void include(String... var1);
    void includeFlat(String... var1);
    File getSettingsDir();
    File getRootDir();
    Gradle getGradle();
    ...
}
复制代码


其中的 include 方法你应该很熟悉了,include 方法指定了参与构建的项目(build.gradle)。在初始化阶段,Gradle 会为「包含」的每个的项目实例化一个 Project 实例。


setting.gradle


include ':app'
复制代码

在 setting.gradle 里,你还可以做这些事:


  • include 指定目录下的项目

Gradle 默认会在工程根目录下寻找 include 包含的项目,那么如果你想包含其他目录下的项目,可以这样配置:


include ':app'
include 'video' 不要加 : 符号
project(:video).projectDir = new File("..\\libs\\video")
复制代码
  • 监听生命周期


在 setting.gradle 里,可以对构建过程中的节点增加监听,监听器添加在Setting.getGradle() 实例上:

setting.gradle


include ':app'
gradle.addBuildListener(new BuildListener() {
    void buildStarted(Gradle var1) {
        println '【开始构建】'
    }
    void settingsEvaluated(Settings var1) {
        // 注意:在这里不能访问 var1.gradle.rootProject,因为 Project 还没有初始化
        println '【settings.gradle 解析完成】'
    }
    void projectsLoaded(Gradle var1) {
        println '【初始化阶段结束】'
    }
    void projectsEvaluated(Gradle var1) {
        println '【配置阶段结束】'
    }
    void buildFinished(BuildResult var1) {
        println '【构建过程结束】'
    }
})
复制代码


构建过程输出(Build Output)如下:


Executing tasks: [:app:generateDebugSources] in project E:\workspace ...
【settings.gradle 解析完成】
【初始化阶段结束】
【这里是配置阶段】
【配置阶段结束】
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:checkDebugManifest UP-TO-DATE
> ...
> Task :app:assembleDebug
【构建过程结束】
BUILD SUCCESSFUL in 14s
24 actionable tasks: 19 executed, 5 up-to-date
复制代码


除了设置监听器方法,还可以直接设置闭包,例如:


gradle.projectsLoaded {
    println '【初始化阶段结束】'
}
复制代码


4.2 配置阶段(Configration phase)


在配置阶段,Gradle 会解析每个项目中的 build.gradle 文件,完成「Project 配置」&「Task 配置」,并根据 Task 依赖关系来创建一个有向无环图。例如:

build.gradle


apply plugin: 'com.android.application'
println '配置 app project'
task hello {
    println '配置 hello task'
    doFirst{
        println 'hello 动作'
    }
}
...
复制代码


构建过程输出(Build Output)如下:


Executing tasks: [:app:assembleDebug] in project E:\workspace\...
【settings.gradle 解析完成】
【初始化阶段结束】
> Configure project :app
配置 app project
配置 hello task
【配置阶段结束】
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:checkDebugManifest UP-TO-DATE
> ...
> Task :app:assembleDebug
【构建过程结束 】
BUILD SUCCESSFUL in 14s
24 actionable tasks: 19 executed, 5 up-to-date
复制代码

易混淆: Task 配置运行在「配置阶段」,Task 动作运行在「执行阶段」。


  • 监听 Task 有向无环图生成


setting.gradle


gradle.getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
    @Override
    void graphPopulated(TaskExecutionGraph graph) {
        println '【Task 有向无环图生成】'
    }
})
复制代码


4.3 执行阶段(Execution phase)


在获得 Task 的有向无环图之后,执行阶段就是根据依赖关系依次执行 Task 动作。


4.4 监听构建过程的耗时情况


long beginOfSetting = System.currentTimeMillis()
def beginOfConfig = false
def configHasBegin = false
def beginOfProjectConfig = new HashMap()
def beginOfProjectExecute
gradle.projectsLoaded {
    println "【初始化阶段结束】,总共耗时:" + (System.currentTimeMillis() - beginOfSetting) + "ms"
}
gradle.beforeProject { project ->
    if (!configHasBegin) {
        configHasBegin = true
        beginOfConfig = System.currentTimeMillis()
    }
    beginOfProjectConfig.put(project, System.currentTimeMillis())
}
gradle.afterProject { project ->
    def begin = beginOfProjectConfig.get(project)
    println "【配置 " + project + "】,耗时:" + (System.currentTimeMillis() - begin) + "ms"
}
gradle.taskGraph.whenReady {
    println "【配置阶段结束】,总耗时:" + (System.currentTimeMillis() - beginOfConfig) + "ms"
    beginOfProjectExecute = System.currentTimeMillis()
}
gradle.taskGraph.beforeTask { task ->
    task.doFirst {
        task.ext.beginOfTask = System.currentTimeMillis()
    }
    task.doLast {
        println "【执行 " + task + "】,耗时:" + (System.currentTimeMillis() - task.beginOfTask) + "ms"
    }
}
gradle.buildFinished {
    // 如果工程中包含 buildSrc 目录,对 buildSrc 项目的构建在这里会 beginOfProjectExecute 空指针
    if(null != beginOfProjectExecute){
        println "【执行阶段结束】,总耗时:" + (System.currentTimeMillis() - beginOfProjectExecute) + "ms"
    }
}
复制代码



5. 总结


  • 初始化阶段: 解析 setting.gradle,为包含的每个项目实例化 Project 实例;
  • 配置阶段: 解析每个项目中的 build.gradle 文件,完成「Project 配置」&「Task 配置」,并根据 Task 依赖关系来创建一个有向无环图;
  • 执行阶段: 根据依赖关系依次执行 Task 动作。


image.png

目录
相关文章
|
6月前
|
存储 缓存 Java
《Gradle构建脚本的基本结构和语法》
《Gradle构建脚本的基本结构和语法》
85 0
|
27天前
|
Java 测试技术 API
云效流水线构建gradle项目失败提示gradle版本过低如何解决
云效(CloudEfficiency)是阿里云提供的一套软件研发效能平台,旨在通过工程效能、项目管理、质量保障等工具与服务,帮助企业提高软件研发的效率和质量。本合集是云效使用中可能遇到的一些常见问题及其答案的汇总。
28 0
|
4月前
|
存储 Java 测试技术
Gradle笔记 四 Gradle的核心 TASK(二)
Gradle笔记 四 Gradle的核心 TASK
42 0
|
4月前
|
Java Maven
Gradle笔记 四 Gradle的核心 TASK(一)
Gradle笔记 四 Gradle的核心 TASK
46 0
|
6月前
|
缓存 Java Maven
深入理解Gradle构建系统的工作原理
深入理解Gradle构建系统的工作原理
155 0
|
8月前
|
设计模式 Java Android开发
基于Gradle的Spring源码下载及构建技巧
首先你的JDK需要升级到1.8以上版本。从Spring 3.0开始,Spring源码采用GitHub托管,不再提供官网下载链接。这里不做过多赘述,大家可自行去GitHub网站下载,我使用的版本下载链接为 https://github.com/spring-projects/spring-framework/archive/v5.0.2.RELEASE.zip ,下载完成后,解压源码包会看到如下图所示的文件目录。
155 0
|
11月前
|
编解码 前端开发 Java
Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目02
Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目02
66 0
|
11月前
|
IDE 前端开发 Java
Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目01
Spring Boot-Spring Tool Suit + Gradle 构建第一个Spring Boot 项目01
70 0
|
Android开发
意外导致了gradle project sync failed. Basic functionality will not work properly
意外导致了gradle project sync failed. Basic functionality will not work properly
意外导致了gradle project sync failed. Basic functionality will not work properly
导入新工程,提示“Migrate Project to Gradle?”
导入新工程,提示“Migrate Project to Gradle?”
89 0