gradle构建脚本和生命周期介绍

参考文档:

    https://www.jianshu.com/p/a132f6a77e7a

一、构建脚本的学习

1.1、概念

  Gradle构建脚本中最重要的两个概念是: project 和 task.任何一个Gradle构建都是有一个或者多个project组成,每个project包含许多的构建部分,可以是一个jar包,也可以是一个war应用,也可以是多个jar的整合等等。

  每个project 由一个或者多个task 组成,每个task表示在构建过程中的一个原子操作。例如:编译、打包、生成javadoc、发布到仓库等操作。

  project 和 project 以及 project 和 task 或者 task 和 task 之间的关系如下:
在这里插入图片描述
  项目1 依赖于 项目2,所以需要先构建项目2,项目2中有三个任务 Task(DEF),由于依赖关系,需要先执行task D,然后是task E,接着是task F, 项目1 中的task也是先执行被依赖的任务。

1.2、Project对象

  一个project 代表着一个正在构建的组件,当构建开始时, Gradle会 基于build.gradle 实例化一个 org.gradle.api.Project 对象,并通过 project变量 来隐式调用其成员,Project的成员属性如下:

名字类型描述
projectProjectproject实例本身
groupObject项目分组
nameString项目名称
versionObject项目版本
pathString项目的绝对路径
descriptionString项目描述
projectDirFile包含生成脚本目录
buildDirFileprojectDir/build
antAntBuilderAntBuilder 实例

1.2.1、Project其他常用配置

  • 1、plugins、apply、plugin 用来引入插件使用(不同版本的引入方式会有些差异)
  • 2、dependencies 依赖配置
  • 3、repositories 仓库配置
  • 4、task 任务书写
  • 5、ext、gradle.properties 用于Project中属性的其他配置方式

   结论:所有的配置都会被封装到 Project 对象中。

1.3、Task对象

  每个任务在构建执行过程中会 被封装成 org.gradle.api.Task 对象,主要包括任务的动作和任务的依赖,任务动作定义了一个原子操作,可以定义依赖其它任务、动作顺序和执行条件。

  Task 主要操作动作

  • dependsOn :依赖相关操作
  • doFirst :执行任务之前执行的方法
  • doLast,<< :执行任务之后执行的方法,gradle 5.0后去掉了 “<<” 的后置方法

1.3.1、自定义task介绍

  gradle 命令会在当前目录中查找一个叫 build.gradle 的文件. 我们称这个 build.gradle 文件为一个构建脚本 (build script), 但是严格来说它是一个构建配置脚本 (build configuration script). 这个脚本定义了一个 project 和它的 tasks.

  所以可以创建build.gradle来编写我们的测试脚本,由于我使用的gradle-6.2.2版本,如果只创建build.gradle会报错,具体报错信息如下:

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project ''.
> The project name must not be empty. Set the 'rootProject.name' or adjust the 'include' statement (see https://docs.gradle.org/6.2.2/dsl/org.gradle.api.initialization.Settings.html#org.gradle.api.initialization.Settings:include(java.lang.String[]) for more details).

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

  所以需要在build.gradle 的同级目录创建一个settings.gradle文件,随便指定一个 rootProject.name,则可以解决报错问题,例如:

rootProject.name = 'hello-gradle'

1.3.2、自定义task

  这里先介绍一下结论,否则再看这个执行结果的时候会让人看得莫名其妙:

  • 所有自定义在build.gradle 中的task,在配置阶段都会执行,其它时候不执行,就算(被)依赖也不执行
  • 只有在 doFirst 和 doLast 中配置的内容再调用任务或者依赖时才会被调用

   结论:所以以后自定义任务执行代码需要填写在doFirst 和 doLast 中,除非想要在构建 Project 时就执行

   1、先创建一个简单的task任务

//	定义一个helloTask的任务
task helloTask{
    println("定义的一个task 任务")
}

   执行helloTask任务

$ gradle helloTask

> Configure project :
定义的一个task 任务

BUILD SUCCESSFUL in 2s

   2、创建一个依赖任务

//	定义一个helloTask的任务
task helloTask {
	doFirst {
		println("helloTask......doFirst")
	}
    doLast {
		println("helloTask......doLast")
	}
}

//	此处task的内容再初始化阶段就会被执行
task helloTask1 {
	println("此处的内容初始化阶段就会被执行")
}

//	定义一个依赖任务,想要执行taskDependsOn 任务,必须先执行helloTask
//	多个依赖的定义方式:task taskDependsOn(dependsOn: ['helloTask'.....]){}
task taskDependsOn(dependsOn: 'helloTask'){
	doFirst{
		println("taskDependsOn......doFirst")
	}
}

   执行taskDependsOn任务

$ gradle taskDependsOn

> Configure project :
此处的内容初始化阶段就会被执行

> Task :helloTask
helloTask......doFirst
helloTask......doLast

> Task :taskDependsOn
taskDependsOn......doFirst

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

   3、多个task的依赖

task A{
    doLast{
        println "A....."
    }
}

task B(dependsOn: A){
    doLast{
        println "B....."
    }
}

task C{
    doLast{
        println "C....."
    }
}
//	多以依赖的写法
task D(dependsOn: [C, B]){
    doLast{
        println "D....."
    }
}

   执行 D 任务

$ gradle D

> Task :A
A.....

> Task :B
B.....

> Task :C
C.....

> Task :D
D.....

BUILD SUCCESSFUL in 2s
4 actionable tasks: 4 executed

1.3.3、动态任务

  借助 Groovy 的强大不仅可以定义简单任务还能做更多的事。例如,可以动态定义任务。

6.times {tempVar ->
	task "task$tempVar" {
		doLast{
			println "I'm task number $tempVar"			
		}
	}
}

  这里动态的创建了task0-task5 ,共6个task,随便执行其中的一个task

$ gradle task2

> Task :task2
I'm task number 2

BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

  这里的 6.times 调用的类是 org.codehaus.groovy.runtime.DefaultGroovyMethods ,具体代码如下:

package org.codehaus.groovy.runtime;
public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
	.......
	public static void times(Number self, @ClosureParams(value = SimpleType.class,options = {"int"}) Closure closure) {
        int i = 0;

        for(int size = self.intValue(); i < size; ++i) {
            closure.call(i);
            if (closure.getDirective() == 1) {
                break;
            }
        }
    }
	.......    
}

1.3.4、给任务自定义属性

  你可以给任务加入自定义的属性. 列如加入一个叫做 myProperty 属性, 设置一个初始值给 ext.myProperty. 然后该属性就可以像一个预定义的任务属性那样被读取和设置了.

task myTask {
	println "hello myTask"
    ext.myProperty = "myValue"
}

task printTaskProperties {
    doLast {
        println myTask.myProperty
    }
}

  执行task

$ gradle printTaskProperties

> Configure project :
hello myTask

> Task :printTaskProperties
myValue

BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

1.3.5、Gradle默认任务

  Gradle 允许在脚本中定义一个或多个默认任务.

defaultTasks 'clean', 'run'

task clean {
	doLast{
		println 'Default Cleaning!'	
	}
}
task run {
	doLast{
		println 'Default Running!'
	}
}
task other {
	doLast{
		println "I'm not a default task!"
	}  
}

  gradle -q 命令的输出

$ gradle -q
Default Cleaning!
Default Running!

  等价于 gradle -q clean run. 在一个多项目构建中, 每一个子项目都可以有它特别的默认任务. 如果一个子项目没有特别的默认任务, 父项目的默认任务将会被执行.

二、gradle项目构建生命周期

  Gradle 的生命周期分为三个阶段:

  • 初始化阶段
  • 配置阶段
  • 执行阶段

2.1、初始化阶段

  通过 settings.gradle 判断哪些项目需要初始化,加载所有需要初始化项目的 build.gradle 文件并为每个项目创建 project 对象

2.2、配置阶段

  执行各项目的 build.gradle 脚本,完成project的配置,并且构造 Task 任务依赖关系图以便在执行阶段按照关系执行Task 中的配置代码.

  配置代码代码如下:

task configCode{
	println 'config Code'
}

2.3、执行阶段

  通过配置阶段的 Task 图,按顺序执行需要执行task中的动作代码,就是执行任务中写的doFirst 和 doLast 中的代码。

  动作代码:任务调用才会被执行的代码;例如:

task exeCode{
	doLast{
		println "exeCode....."
	}
}

  以上就是 Gradle 构建项目时的生命周期,由于Gradle 的强大和易配性,如果想在构建的过程中去做一些额外的操作的话可以使用Gradle 自带的钩子方法.以下咱们通过一个图来描述 Gradle 的生命周期和钩子方法.

2.4、Gradle 生命周期和钩子方法

Gradle 生命周期和钩子方法
  上图表明了Gradle 构建的整个流程,在生命周期的三个阶段中有很多的钩子方法供用户自行覆盖使用.

  注意:

  • 1 初始化阶段的钩子方法和 gradle.beforeProject() 只能定义在 setting.gradle 或 init.gradle 脚本中.
    执行 build.gradle 时已经有了 project 对象.且执行前就调用了beforeProject钩子方法.

  • 2 gradle.buildStarted() 钩子方法无法执行到.通过源码得知,在初始化前就已经调用了 buildStarted 方法,所以在初始化阶段无法回调的到.

  例子

  setting.gradle

rootProject.name = 'hello-gradle'

// 初始化阶段
gradle.settingsEvaluated {
    println '初始化阶段settingsEvaluated'

}
gradle.projectsLoaded  {
    println '初始化阶段 projectsLoaded'
}

// 配置阶段
gradle.beforeProject {
    println '配置阶段 beforeProject'
}

  build.gradle

// 自定义任务
task t1 {
    println 't1 configuration'
    doLast {
        println 't1 execute doLast'
    }
    doFirst {
        println 't1 execute doFirst'
    }
}
// 钩子方法
gradle.afterProject {
    println '配置阶段 afterProject'
}
project.beforeEvaluate {
    println '配置阶段 beforeEvaluate'
}
gradle.projectsEvaluated {
    println '配置阶段 projectsEvaluated'
}
project.afterEvaluate {
    println '配置阶段 afterEvaluate'
}
gradle.taskGraph.whenReady {
    println '配置任务 whenReady'
}

// 执行阶段
gradle.taskGraph.beforeTask {
    println "执行阶段 before task"
}
gradle.taskGraph.afterTask {
    println "执行阶段 afterTask "
}
gradle.buildFinished {
    println '构建结束 buildFinished'
}

  执行 gradle t1 结果如下:

$ gradle t1
Starting a Gradle Daemon (subsequent builds will be faster)
初始化阶段settingsEvaluated
初始化阶段 projectsLoaded

> Configure project :
配置阶段 beforeProject
t1 configuration
配置阶段 afterProject
配置阶段 afterEvaluate
配置阶段 projectsEvaluated
配置任务 whenReady

> Task :t1
执行阶段 before task
t1 execute doFirst
t1 execute doLast
执行阶段 afterTask
构建结束 buildFinished

BUILD SUCCESSFUL in 13s
1 actionable task: 1 executed

  以上就是Gradle 项目构建的生命周期和钩子方法的介绍,这些钩子方法一般使用得少,特殊需求情况下可以使用.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值