gradle学习之旅(七) 挂接到构建生命周期
gradle提供了构建生命周期的钩子来支持执行构建生命周期中某事件发生时想要执行的代码。一个生命周期事件可能发生在某个构建阶段之前、期间或者之后。在执行阶段之后发生的生命周期事件是构建的完成。
有两种方式可以编写回调生命周期事件:
- 将代码写在闭包中
- 实现Gradle API所提供的监听器接口
具体Gradle提供了哪些钩子可以通过官方文档API查看,下面使用与task执行图有关的钩子来学习生命周期钩子的使用。
Task执行图
在配置阶段,gradle决定了在执行阶段要运行的task顺序。这个顺序被建模为一个表示依赖关系的有向无环图(DAG)。图中的每个Task被称为一个节点,且该图没有闭环,也就是说先前执行的task不会再次执行。
挂接到task执行图
Gradle API对task执行图有对应的领域模型对象,可以通过project.gradle.taskGraph
来访问task执行图对象。
- 例子:之前所实现的makeReleaseVersion task,是作为发布task的依赖被自动执行。在了解了生命周期钩子后,可以编写一个生命周期钩子来实现这个makeReleaseVersion task同样的目标。调用taskGraph的whenReady(Closure)方法,可以在taskGraph生成完成之后执行该方法传入的闭包。
gradle.taskGraph.whenReady{ TaskExecutionGraph taskGraph ->
if(taskGraph.hasTask(release)) { //查看taskGraph中是否有发布任务
if(!version.release){
version.release = true
ant.propertyfile(file: versionFile) {
entry(key: 'release',type:'string' , operation: '=' , value:'true')
}
}
}
}
实现taskGraph监听器来挂接
通过监听器挂接到生命周期需要两步:
- 编写一个类来实现特定的监听器接口
用于监听taskGraph事件的接口是由TaskExecutionGraphListener接口提供的,其他的事件监听接口不列举,用到的时候查阅API。
需要实现TaskExecutionGraphListener接口的graphPopulated(TaskExecutionGraph)方法,具体用法如下:
class ReleaseVersionListener implements TaskExecutionGraphListener{
final static String releaseTaskPath = ':release'
@Override
void graphPopulated(TaskExecutionGraph taskGraph){
if(taskGraph.hasTask(releaseTaskPath)){ //确定release task是否包含在taskGraph中
List<Task> allTasks = taskGraph.allTasks
Task releaseTask = allTask.find{it.path == releaseTaskPath}
Project project = releaseTask.project //通过task来访问project
if(!project.version.release){
project.version.release = true
project.ant.propertyfile(file: project.versionFile) {
entry(key: 'release',type:'string' , operation: '=' , value:'true')
}
}
}
}
}
在监听器中不能直接访问Project实例,但是可以通过GradleAPI,通过task来访问该task所属的project。
- 注册监听器实现
使用project.gradle.addListener(listener: Object)方法或者project.gradle.taskGraph.addTaskExecutionGraphListener(listener: TaskExecutionGraphListener) 来注册监听器,代码如下
.gradle.taskGraph.addTaskExecutionGraphListener(new TaskExecutionGraphListener())
初始化构建环境
- 初始化脚本:
在目录<USER>_HOME>/.gradle/init.d
下的以.gradle为扩展名的脚本,会被gradle视为初始化脚本。gradle会在任何构建脚本逻辑解析执行之前运行所有的初始化脚本。在初始化脚本中写入代码相当于将代码挂载到所有的构建生命周期的开始。
- 例子:将插件java应用到构建的根项目中
- 在init.d目录下创建脚本java.gradle
- 在java.gradle文件中写入下列代码
gradle.projectsLoaded{ //选择使用这个生命周期回调方法来处理这种情况 Gradle gradle -> gradle.rootProject { //由于这是gradle全局脚本,无法访问项目实例,只能通过GradleAPI来访问根项目 apply plugin: 'java' } }
一些生命周期时间只有在适当位置生命才会触发,比如讲上面代码的gradle.projectsLoaded事件生命在build.gradle中则不会被触发,因为项目加载在初始化阶段,而build.gradle文件在配置阶段才会处理。