gradle学习之旅(六) 使用Task(上)

本节以软件项目的版本管理作为例子来学习gradle的task的使用

gradle构建生命周期

想要理解task的使用方法,理解gradle'build lifecycle phases(gradle构建生命周期各阶段)是至关重要的,无论什么时候执行gradle构建,都会运行三个不同的生命周期:如下

  • 初始化阶段(Initialization phase)
    这个阶段,gradle在内存中为项目创建了一个Project实例。根据在执行的项目,gradle找出哪些项目依赖需要参与到构建中,在这个阶段当前已有的构建脚本代码并不会被执行。
  • 配置阶段(Configuration phase)
    初始化阶段完成后,进入配置阶段。在这个阶段gradle构造任务的实例,所以这个阶段非常适合于为项目或task设置所需的配置。
    需要明确,写在gradle构建脚本中的代码分两种:配置代码和动作代码
    • 配置代码(Configuration code):
      在配置阶段执行的代码,除动作代码之外的代码都是配置代码。注意,项目每一次构建的任何配置代码都可以被执行,即使你只指定gradle tasks
    • 动作代码(Action code)
      Task接口提供了两个相关的方法来声明task动作:doFirst(Closure)和doLast(Closure),当task被执行时,动作逻辑被定义为闭包参数被依次执行。
  • 执行阶段(Execution phase)
    在执行阶段,所有的task的动作逻辑都应该以正确顺序被执行,执行顺序由它们的依赖决定的。如果任务被认为没有修改过,则将被跳过。

声明task动作(action)

version = '0.1-SNAPSHOT'
task printVersion{
	doLast{
	 println "Version: $version"
	}
}

添加动作

printVersion.doFirst { println "First action" }
printVersion << { println "Last version" }

在内部,每个task都保持了一个动作列表,在运行时,他们按顺序执行。

访问DefaultTask属性

关于DefaultTask的全部属性可以通过查看源代码或者在官网的gradleAPI文档查看。
Gradle的Project和Task都提供了一个logger属性,logger是一个基于SLF4J日志库的logger实现。除了实现常规范围内的日至级别(DEBUG、ERROR、INFO、TRACE、WARN)之外,Gradle还增加了一些额外的日至级别。直接调用logger,就相当于调用它的get方法。(牢记在groovy中访问属性是groovy提供的语法糖)

下面使用logger打印QUIET日志级别版本号

task printVersion << {
	logger.quiet "Version: $version"
}

Task的属性group制定了该task的分组,description指定task描述。在使用命令gradle tasks时可以看到task的分组与描述。在创建时可以用如下方式给task的属性赋值:

task printVersion(group: 'versioning',description:'Prints project version'){
    logger.quiet "Version:$version"
}

或者去掉语法糖

task ([group: 'versioning',description:'Prints project version'],'printVersion',{
    logger.quiet "Version:$version"
})

或者直接在委托闭包中使用set来赋值

task printVersion{
	group = `versioning`
	description = 'Prints project version.'
	doLast {
		logger.quiet "Version:$version"
	}
}

定义task的紧前与紧后

这里借用工作流程中紧前工序与紧后工序来理解下面两个概念:

  • task依赖(task dependencies):
    相当于目前task的紧前task。
    dependsOn方法允许声明依赖一个或多个task,或者使用dependsOn的set方法来设置task的依赖,下面的例子体现了这两种声明task依赖方式:
task first << {println "first"}
task second << {print "second"}
task printVersion(dependOn: [second,first]) << {
	logger.quiet "Version: $version"
}

这种方式属于调用dependsOn的set方法来声明依赖,这是一种类似于groovy"命名参数"语法糖的一种糖,实际上调用了Task的如下方法:

或者像下面这样声明依赖:

task third << { println "third" }
third.dependOn('printVersion')

这种方式是调用Task的dependOn方法:

需要明确一点,dependsOn方法只是定义了所以来的task需要先执行,而没有定义真正的task执行顺序,在gradle中,执行顺序是由task的 input/output 自动确定的。

  • 终结器task(Finalizer tasks):
    定义终结器task相当于定义目前task的紧后task
    与dependsOn类似,gradle提供了finalizedBy来声明终结器task,用法也和dependsOn相同,因为它们的源码形式都相同:

添加任意代码

在gradle构建脚本中可以添加面向对象代码来实现对POJO的抽象,提高代码复用性。当然也可以把这些封装的类写在单独的文件中,在这里先写在构建脚本中

version = new ProjectVersion(0,1) //在gradle中version属性类型是Object,输出它默认使用toString方法
class ProjectVersion{
	Integer major
	Integer minor
	Boolean release
	ProjectVersion(Integer major, Integer minor){
		this.major = major
		this.minor = minor
		this.release = Boolean.FALSE
	}
	ProjectVersion(Integer major, Integer minor,Boolean release){
	this.major = major
		this.minor = minor
		this.release = release
	}
	@oberride
	String toString(){
		"$major.$minor${release? '' : '-SNAPSHOT'}"
	}
}

添加task配置

在前面了解了gradle生命周期,明确了配置代码与动作代码的区别,所以在为项目添加版本号时,可以把版本号写在外部文件中,然后在gradle配置代码中读取它,然后再利用读取到的版本号执行task动作代码,这样可以避免因为版本更替而需要修改构建脚本的问题。

  • 创建一个名为version.properties的属性文件,并写入如下内容作为最初的版本属性:
major = 0
minor = 1
release = false
  • 定义一个新的project属性,用来代表属性文件的File对象,添加一个loadVersion task ,用作task配置:
ext.versionFile = file('version.properties')
task loadVersion {
	project.version = readVersion()
}
ProjectVersion readVersion() {
	logger.quiet 'Reading the version file'
	if(!versionFile.exists()){
	throw new GradleException("Required version file does not exist : $versionFile.canonicalPath")
	Properties versionProps = new Properties()
	versionFile.withInputStream{
	stream  ->
	versionProps.load(stream)
	}
	new ProjectVersion(versionProps.major.toInteger(),
									versionProps.minor.toInteger(),
									versionProps.release.toBoolean())
	}
}

这时,若使用命令gradle printVersion,就会发现loadVersion和printVersion被调用。这是因为loadVersion中的配置代码会在配置阶段就被调用,及时使用命令gradle tasks,如果不加限制,所有的配置代码都会执行。
如:在脚本中写入

task printVersion(group: 'versioning',description:'print current version'){
    logger.quiet "Version:$version"
}
printVersion{
    println "END printVersion"
}

然后执行gradle tasks,输出如下:

下一节继续学习task的高级使用方法,包括增量式构建、自定义Task、gradle内置task类型、task依赖推断、task规则等内容

原文地址:https://www.cnblogs.com/Theshy/p/7890819.html