Gradle学习笔记之Hook生命周期

news2024/9/22 23:31:30

简介

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/181893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022爱分析・智能客服厂商全景报告 | 爱分析报告

报告编委 张扬 爱分析联合创始人&首席分析师 文鸿伟 爱分析高级分析师 王鹏 爱分析分析师 目录 研究范围定义厂商全景地图市场分析与厂商评估入选厂商列表研究范围定义 研究范围 在数字化快速发展的大背景下,随着消费人群及其消费意识的转变,客户对…

亚马逊云科技凭借多年云业务经验,协同合作伙伴快速展开生态化创新

在过去的两周里,ChatGPT的热度居高不下,引发全网讨论。虽然AlphaGo这类AI产品也曾引起热议,但是在应用层面终究还是离用户太远了。而ChatGPT更像是「民用级」的产品,真正意义上让AI技术跨入广泛破圈应用时代。在当下,机…

大数据-Hive

第1章 Hive入门 1.1 什么是Hive 1)Hive简介 Hive是由Facebook开源,基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。 2)Hive本质 Hive是一个Hadoop客户端,用于…

springboot项目解决@ResponseBody注解返回xml格式数据而不是json格式的问题

目录 1.说明 2.解决 1.说明 一般情况下,RestController中的接口默认响应数据格式都是 json 格式的数据,但有时候使用某些依赖包,会影响ResponseBody的响应数据类型为xml格式, 例: 2.解决 但我们希望响应数据格式是…

使用腾讯云服务器+Nonebot2+go-cqhttp搭建QQ聊天机器人

文章目录一、查看conda版本二、查看系统版本三、配置go-cqhttp1.请切换至同一网络下扫码2.打包Docker镜像四、创建NoneBot环境安装脚手架一、查看conda版本 二、查看系统版本 uname -a arch getconf LONG_BIT三、配置go-cqhttp 下载go-cqhttp 这里有不同版本的cqhttp,并且对…

【数据结构】——如何设计一个链表?(设计链表)

本文主题:通过一道题目,学习链表的基本操作 更多算法:动态规划 ✔️ 边界控制 我的主页:蓝色学者的主页 文章目录一、前言二、题目信息三、解决方案3.0什么是链表?3.1节点的概念虚拟头节点3.2链表创建3.3头插/尾插3…

JUC面试(十三)——锁膨胀

锁膨胀 monitor概念 Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。上面这个图,描述了线程和 Monitor之间关系,以及线程的状态转换图。 进入区…

windows11 永久关闭windows defender的方法

1、按键盘上的windows按键,再点【设置】选项。 2、点击左侧菜单的【隐私和安全性】,再点击列表的【Windows安全中心】选项。 3、点击界面的【病毒和威胁保护】设置项。 4、病毒保护的全部关闭 5、别人的图(正常是都开着的) 6、终极…

为什么看上去很简单的智慧功能点要价上千万?

人工智能(Artificial Intelligence,AI)已经不是什么新概念,第三次浪潮于2016年AlphaGo战胜李世石为标志正式开启,至今也已经走过6个年头。 发展至今,AI已经进入老百姓的日常生活,比如随处可见的…

【C语言】从0到1带你学会文件版动态通讯录

🌇个人主页:平凡的小苏 📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情 🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html 小苏希望大家能从这篇文章中收获到许…

初学者试试,HarmonyOS应用开发者基础认证

一些初学HarmonyOS应用开发的同学往往不知道如何开始,建议先试试《HarmonyOS应用开发者基础认证》,基础认证是华为进一步大范围布局推广“鸿蒙世界”的新举措。也是初学者开启鸿蒙世界的一把钥匙。 【说说鸿蒙世界】 相信大家已经对鸿蒙不陌生了&#x…

IDEA新建js项目和执行js脚本

一)、安装Node.js具体操作参考:https://blog.csdn.net/xijinno1/article/details/128774375二)、IDEA中新建js项目(hello world)1.按照下图,新建js项目2.选中示例代码文件后点击运行->运行3.选择【编辑配置】4.更新一下节点解释器(nodejs.exe),点击运…

界面组件DevExpress WPF v22.2 - Windows 11暗黑主题发布

DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

Unity 之 Addressable可寻址系统 -- 资源远程加载 | 资源预下载

可寻址系统远程加载 -- 资源预下载 -- 进阶(三)一,Unity 云资源分发 -- 使用介绍1.1 CCD 的介绍1.2 后台准备工作二,CDD的使用2.1 CCD可视化界面的使用2.2 CDD命令行界面使用2.2.1 准备工作2.2.2 CLI 用法三,AA CCD资…

Qt扫盲-QObject对象和线程

QObject对象和线程一、概述二、QObjectReentrant性三、每个线程事件的循环四、从其他线程访问QObject的子类五、跨线程的信号和槽函数一、概述 QThread继承QObject。QThread它发出信号来指示线程开始或结束执行,还提供了一些任务槽。 Qobject可以在多个线程中使用…

L1-006 连续因子

一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3567,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。 输入格式: 输入在一行中给出一…

Python爬虫(1)一次性搞定Selenium(新版)8种find_element元素定位方式

selenium中有8种不错的元素定位方式,每个方式和应用场景都不一样,需要根据自己的使用情况来进行修改 这里写目录标题1.id定位2.CSS定位3.XPATH定位4.name定位5.class_name定位6.Link_Text定位7.PARTIAL_LINK_TEXT定位8.TAG_NAME定位总结目前selenium已经…

力扣SQL刷题

目录标题571. 给定数字的频率查询中位数574. 当选者608. 树节点612. 平面上的最近距离619. 只出现一次的最大数字571. 给定数字的频率查询中位数 题型:给出数值和对应频率,返回中位数 解答:分别升序和降序排列。中位数正序和倒序所处的位置都…

人工智能图片素材高清,机器人图片卡通 素材

1、做一个人工智能的ppt需要哪些素材 不能理解你的问题。ppt仅仅是一个做幻灯的软件,可以插入图片、动画、音乐、过场等幻灯的功能,还谈不上有人工智能的能力。人工智能需要有更为强大的类似人脑思维的能力,简单的说人工智能是可以思考的机器…

【HBase——陌陌海量存储案例】2. HBase表结构设计(中)

前言 本文是陌陌海量存储案例——HBase表结构设计(中),介绍ROWKEY设计原则、项目初始化。 4.5 ROWKEY设计原则 4.5.1 HBase官方的设计原则 避免使用递增行键/时序数据 如果ROWKEY设计的都是按照顺序递增(例如:时间…