Gradle学习笔记之Hook生命周期

简介

Gradle生命周期中的hook(钩子)函数是由gradle自动回调的,可以用来帮助我们实现一些功能:
在这里插入图片描述
Gradle在生命周期各个阶段都提供了用于回调的钩子函数:

  • Gradle初始化阶段:
    • settings.gradle执行完后,会回调Gradle对象的settingsEvaluated方法;
    • 在构建所有工程build.gradle对应的Project对象后,即初始化阶段完毕,会回调Gradle对象的projectsLoaded方法。
  • Gradle配置阶段:
    • Gradle会循环执行每个工程的build.gradle脚本文件;
    • 在执行当前工程build.gradle前,会回调Gradle对象的beforeProject方法和当前Project对象的beforeEvaluate方法。虽然beforeEvalute属于project的生命周期,但是此时buildscript尚未被加载,所以beforeEvaluate的设置依然要在init scriptsetting script中进行,不要在 build script中使用project.beforeEvaluate方法;
    • 在执行当前工程build.gradle后,会回调Gradle对象的afterProject方法和当前Project对象的afterEvaluate方法;
    • 在所有工程的build.gradle执行完毕后,会回调Gradle对象的projectsEvaluated方法;
    • 在构建Task依赖有向无环图后,也就是配置阶段完毕,会回调TaskExecutionGraph对象的whenReady方法。
  • Gradle执行阶段:
    • Gradle会循环执行Task及其依赖的Task
    • 在当前Task执行之前,会回调TaskExecutionGraph对象的beforeTask方法;
    • 在当前Task执行之后,会回调TaskExecutionGraph对象的afterTask方法;
    • 当所有的Task执行完毕后,会回调Gradle对象的buildFinish方法。

提示:Gradle执行脚本文件的时候会生成对应的实例,主要有如下几种对象:

  1. Gradle对象:在项目初始化时构建,全局单例存在,只有这一个对象;
  2. Project对象:每一个build.gradle文件都会被转换成一个Project对象,类似于maven中的pom.xml文件;
  3. Settings对象:settings.gradle会转变成一个settings对象,和整个项目是一对一的关系,一般只用到include方法;
  4. Task对象: 从前面的有向无环图中,我们也可以看出,gradle最终是基于Task的,一个项目可以有一个或者多个Task

举例

HookAPI验证

前文所述的GradleTest项目为例,在根项目的settings.gradle中添加:

gradle.settingsEvaluated {
    // 1.settingsEvaluated钩子函数,在初始化阶段完成
    println "settingsEvaluated"
}

gradle.projectsLoaded {
    // 2.projectsLoaded钩子函数,在初始化阶段完成
    println "projectsLoaded"
}

// 声明一个变量:表示当前项目名,在每次执行某个项目的beforeEvaluate方法时先给projectName变量赋值
// 这样方便在gradle.beforeProject和afterProject两个钩子函数使用。
def projectName= ""
gradle.addProjectEvaluationListener(
        new ProjectEvaluationListener() {
            //3.执行各个project的beforeEvaluate:在配置阶段完成
            @Override
            void beforeEvaluate(Project project) {
                projectName=project.name
                println "${project.name} Project beforeEvaluate"
            }
            
            // 5.执行各个project的afterEvaluate:在配置阶段完成
            @Override
            void afterEvaluate(Project project, ProjectState projectState) {
                println "${project.name} Project afterEvaluate" }
        });

gradle.beforeProject {
    // 4.执行各个project的beforeProject:在配置阶段完成
    println "${projectName} beforeProject..."
}

gradle.afterProject {
    // 6.执行各个project的afterProject:在配置阶段完成
    println "${projectName} afterProject..."
}

// 7.所有工程的 build.gradle 执行完毕后,回调Gradle对象的projectsEvaluated方法:在配置阶段完成
def rootProjectName= rootProject.getName()
gradle.projectsEvaluated {
    println "${rootProjectName} projectsEvaluated..."
}

// 8.配置阶段完毕后,回调TaskExecutionGraph对象的whenReady方法:在配置阶段完成
gradle.taskGraph.whenReady {
    println "${rootProjectName} taskGraph whenReady..."
}

// 9.在当前Task执行之前,会回调TaskExecutionGraph对象的beforeTask方法:在执行阶段完成
gradle.taskGraph.beforeTask {
    task -> println "this is the task ${task.name} of the project ${task.getProject().name} beforeTask.."
}

// 10.在当前Task执行之后,会回调TaskExecutionGraph对象的afterTask方法:在执行阶段完成
gradle.taskGraph.afterTask {
    task -> println "this is the task ${task.name} of the project ${task.getProject().name} afterTask.."
}

// 11.当所有的 Task 执行完毕后,会回调Gradle对象的buildFinish方法:在执行阶段完成
gradle.buildFinished {
    println "${rootProjectName} buildFinished..."
}

在根项目的build.gradle中添加:

task "A" {
    println "root taskA"
    doFirst() {
        println "root taskA doFirst"
    }

    doLast() {
        println "root taskA doLast"
    }
}

lib1build.gradle中添加:

task "B" {
    println "lib1 taskB"

    doFirst() {
        println "lib1 taskB doFirst"
    }

    doLast() {
        println "lib1 taskB doLast"
    }
}

lib2build.gradle中添加:

//task C在上面
task "C" {
    //依赖task D
    dependsOn 'D'

    println "lib2 taskC"

    doFirst() {
        println "lib2 taskC doFirst"
    }

    doLast(){
        println "lib2 taskC doLast"
    }
}

//task D在下面
task "D" {
    println "lib2 taskD"
    doFirst() {
        println "lib2 taskD doFirst"
    }

    doLast(){
        println "lib2 taskD doLast"
    }
}

而后,在根项目中执行gradle C -q,查看输出结果:

(base) PS D:\develop\ideaWorkspace\GradleTest> gradle C -q
settingsEvaluated
projectsLoaded
GradleTest Project beforeEvaluate
GradleTest beforeProject...
root taskA
GradleTest Project afterEvaluate
GradleTest afterProject...
lib1 Project beforeEvaluate
lib1 beforeProject...
lib1 taskB
lib1 Project afterEvaluate
lib1 afterProject...
lib2 Project beforeEvaluate
lib2 beforeProject...
lib2 taskC
lib2 taskD
lib2 Project afterEvaluate
lib2 afterProject...
lib3 Project beforeEvaluate
lib3 beforeProject...
lib3 Project afterEvaluate
lib3 afterProject...
myplugin Project beforeEvaluate
myplugin beforeProject...
myplugin Project afterEvaluate
myplugin afterProject...
lib1_1 Project beforeEvaluate
lib1_1 beforeProject...
lib1_1 Project afterEvaluate
lib1_1 afterProject...
lib1_2 Project beforeEvaluate
lib1_2 beforeProject...
lib1_2 Project afterEvaluate
lib1_2 afterProject...
GradleTest projectsEvaluated...
GradleTest taskGraph whenReady...
this is the task D of the project lib2 beforeTask..
lib2 taskD doFirst
lib2 taskD doLast
this is the task D of the project lib2 afterTask..
this is the task C of the project lib2 beforeTask..
lib2 taskC doFirst
lib2 taskC doLast
this is the task C of the project lib2 afterTask..
GradleTest buildFinished...

可以看到gradle生命周期的三个阶段,以及每个阶段的hook函数,以及执行阶段各任务的执行顺序。

我们可以在settings.gradle中添加监听器,以查看taskDAG

gradle.taskGraph.addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
    @Override
    void graphPopulated(TaskExecutionGraph taskExecutionGraph) {
        taskExecutionGraph.allTasks.forEach(task -> {
            println "task $task.name in project $task.project.name"
        })
    }
})

运行任务C时的输出如下:

(base) PS D:\develop\ideaWorkspace\GradleTest> gradle C -q
......
task D in project lib2
task C in project lib2
......

任务耗时统计

统计各项目或任务的配置和执行阶段运行耗时,可以在根项目的settings.gradle中添加:

def projectName = rootProject.getName() // 定义项目名
long beginOfSetting = System.currentTimeMillis() // 初始化阶段开始时间
def beginOfConfig // 配置阶段开始时间
def configHasBegin = false // 配置阶段是否开始了
def beginOfProjectConfig = new HashMap() // 存放每个build.gradle执行之前的时间
def beginOfTaskExecute // 执行阶段开始时间

gradle.projectsLoaded {
    // 初始化阶段执行完毕
    println "${projectName}工程 初始化总耗时 ${System.currentTimeMillis() - beginOfSetting} ms"
}

// build.gradle执行前
gradle.beforeProject {
    Project project -> {
        if(!configHasBegin){
            configHasBegin = true
            beginOfConfig = System.currentTimeMillis()
        }
        beginOfProjectConfig.put(project, System.currentTimeMillis())
    }
}

//build.gradle 执行后
gradle.afterProject {
    Project project -> {
        def begin = beginOfProjectConfig.get(project)
        if (project.name == projectName) {
            println "根工程${projectName} 配置阶段耗时:${System.currentTimeMillis() - begin} ms"
        } else {
            println "子工程${project.name} 配置阶段耗时:${System.currentTimeMillis() - begin} ms"
        }
    }
}

gradle.taskGraph.whenReady {
    // 配置阶段完毕
    println "整个${projectName}项目在配置阶段总耗时:${System.currentTimeMillis() - beginOfConfig} ms"
    beginOfTaskExecute = System.currentTimeMillis()
}

// 执行阶段开始
gradle.taskGraph.beforeTask {
    Task task -> {
            task.doFirst {
                task.ext.beginOfTask = System.currentTimeMillis()
            }
            task.doLast {
                println "${task.name}在执行阶段耗时:${System.currentTimeMillis() - task.ext.beginOfTask} ms"
            }
    }
}

gradle.buildFinished {
    // 执行阶段完毕
    println " 执行阶段总耗时:${System.currentTimeMillis() - beginOfTaskExecute} ms"
    println " 整个构建过程耗时:${System.currentTimeMillis() - beginOfSetting} ms"
}

执行任务C时的输出结果:

(base) PS D:\develop\ideaWorkspace\GradleTest> gradle C -q
GradleTest工程 初始化总耗时 24 ms
根工程GradleTest 配置阶段耗时:54 ms
子工程lib1 配置阶段耗时:4 ms
子工程lib2 配置阶段耗时:5 ms
子工程lib3 配置阶段耗时:5 ms
子工程myplugin 配置阶段耗时:6 ms
子工程lib1_1 配置阶段耗时:6 ms
子工程lib1_2 配置阶段耗时:5 ms
整个GradleTest项目在配置阶段总耗时:94 ms
D在执行阶段耗时:1 ms
C在执行阶段耗时:1 ms
执行阶段总耗时:12 ms
整个构建过程耗时:278 ms
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值