需要准备
- 一个熟悉的 IDE 开发工具
- JDK 7及以上
- Gradle 3.2以上
Gradle构建的各生命周期
1.初始化阶段
在初始化阶段,Gradle 决定哪些工程将会参与到构建,然后为每一个工程创建一个Project
的对象,通过该对象可以访问到工程的 Gradle 配置的所有功能。
2.配置阶段
在这个阶段,进行工程配置,工程的构建脚本会被执行。在这个阶段会遵循“按需配置”原则,Gradle 仅会配置相关联的工程。
3.执行阶段
在这个阶段,Gradle 会决定哪些分组任务被执行,这些分组任务是在配置阶段创建和配置好的。我们通过在 Gradle 命令行中传递任务的名称和当前目录来执行任务。
按需配置的原则
由于 Gradle 任务执行前所有工程的配置过程都会被执行,所以如果我们的项目有上百个工程(微服务会拆分很多工程)时,每次执行任务都要先进行上百个工程的配置过程,这样会浪费很多的时间,所 Gradle1.4 版本之后引进了“按需配置”功能。
按需配置是指每次执行任务前仅对相关依赖的工程进行配置,这样就节省了很多没必要的时间浪费。具体的配置原则如下:
- 根工程( root project )永远都会进行配置。这样我们就能在根工程中进行一些共享的公共配置,比如使用
allprojects
或者subprojects
进行的配置项。 - 在执行构建命令的当前工程会被进行配置,意思就是我们在哪个子工程中执行了
gradle build
命令,那么该工程也会被进行配置。 - 相关依赖工程会进行配置,比如,A 工程构建时依赖于 B 工程,那么在构建 A 工程之前,也会同时对 B 工程进行配置。
- 声明了相关任务依赖的工程也会进行配置,比如
someTask.dependsOn(":someOtherProject:someOtherTask")
,在进行构建之前 someOtherProject 工程也会同时进行配置。
在介绍了以上工程构建时的理论基础后,我们接下来从具体的配置实例来介绍多工程的构建打包过程。
定义公共的配置方法
首先我们创建根工程为multiproject
的项目,该项目包含三个子工程,分别为:api、core 和 game。其结构如下:
multiproject/
build.gradle
settings.gradle
api/
core/
game/
其中有一个名为settings.gradle
的配置文件,我们在之前的单工程中并没有介绍过,因为在单工程中它不是必须的,而在多工程中则是必须的,它指定了项目包含的所有子工程。并且 settings 配置文件是在初始化阶段进行加载的。其内容如下:
settings.gradle
include 'api', 'core', 'game'
1.在根工程中使用allprojects
进行配置
由于在工程的 API 中提供了一个allprojects
属性,它返回了当前工程和当前工程的所有子工程的列表。我们可以通过 allprojects 的闭包方式来为所有工程设置配置项。代码示例如下:
allprojects {
task hello {
doLast { task ->
println "I'm $task.project.name"
}
}
}
执行命令gradle -q hello
结果如下:
$ gradle -q hello
I'm multiprojects
I'm api
I'm core
I'm game
2.在根工程中使用subprojects
进行配置
同样的,在工程 API 中也提供了一个subprojects
属性,它返回当前工程的所有子工程列表,它的用法和 allprojects 相似。接下来我们为根工程再添加一个 subprojects 配置项,在其中为hello
任务新增一个doLast
方法,代码如下:
allprojects {
task hello {
doLast { task ->
println "I'm $task.project.name"
}
}
}
subprojects {
hello {
doLast {
println "- I a subproject"
}
}
}
再执行命令gradle -q hello
结果如下:
$ gradle hello
I'm multiprojects
I'm api
- I a subproject
I'm core
- I a subproject
I'm game
- I a subproject
3.在根工程中指定特定工程的配置
上面两种方法要么为所有工程、要么为所有子工程添加公共配置,可不可以只为某一个工程添加呢?答案是肯定的,其代码如下:
project(':game').hello {
doLast {
println "- $project.name, I'm the specific project."
}
}
执行命令gradle -q hello
结果如下:
$ gradle hello
I'm multiprojects
I'm api
- I a subproject
I'm core
- I a subproject
I'm game
- I a subproject
- game, I'm the specific project.
在最后一行看到了我们为子工程 game 添加的特殊方法,这里使用了:game
的方式进行设置的。不过真实项目中一般不会这么做,而是在子工程中创建一个 build.gradle 的脚本文件,在其中实现特定子工程的配置。
4.通过工程过虑
configure
方法接受一个列表作为参数,然后可以把配置项应用到列表中的工程中。代码如下:
allprojects {
task hello {
doLast { task ->
println "I'm $task.project.name"
}
}
}
subprojects {
hello {
doLast {
println "- I a subproject"
}
}
}
configure(subprojects.findAll {it.name == 'core'}) {
hello {
doLast {
println "- $project.name, I'm the configure project."
}
}
}
执行命令gradle -q hello
结果如下:
$ gradle hello
I'm multiprojects
I'm api
- I a subproject
I'm core
- I a subproject
- core, I'm the configure project.
I'm game
- I a subproject
其中可以看到只在 core 子工程中添加了 doLast 方法。
使用相对路径来执行指定的任务
一个工程的路径为:以冒号(: 它代表了根工程)开始,再加上工程的名称。例如“:core”。
一个任务的路径为:工程路径加上任务名称,例如“:game:hello”.
我们可以通过指定任务路径来执行任务,代码如下:
$ gradle :game:hello
:game:hello
I'm game
- I a subproject
多工程的依赖关系
1.配置依赖和执行依赖
配置依赖和执行依赖是不同的,一般来说,配置依赖是指工程间的,而执行依赖主要是任务之间的相互依赖。
依赖顺序是从上到下的,也就是在子工程中执行构建的时候,父级的所有工程会先进行配置;而相同级别的工程则按照“字母数字”表顺序进行配置,也就是工程名为 a 的必然比工程名为 b 的先进行配置。
下面举例说明配置依赖和执行依赖的关系,首选创建如下项目结构:
webDist/
settings.gradle
build.gradle
date/
src/main/java/
org/gradle/sample/
DateServlet.java
hello/
src/main/java/
org/gradle/sample/
HelloServlet.java
settings.gradle
include 'date', 'hello'
build.gradle
allprojects {
apply plugin: 'java'
group = 'org.gradle.sample'
version = '1.0'
}
subprojects {
apply plugin: 'war'
repositories {
mavenCentral()
}
dependencies {
compile "javax.servlet:servlet-api:2.5"
}
}
task explodedDist(type: Copy) {
into "$buildDir/explodedDist"
subprojects {
from tasks.withType(War)
}
}
从代码中可以很明显看出,date 和 hello 工程配置依赖于 webDist 根工程,因为所有的配置都是通过 webDist 工程进行注入的。但是从执行配置上正好相反,因 webDist 工程的构建部件上依赖于 date 和 hello。
2.工程库依赖
如果一个工程编译所需的 jar 为另一个工程所产生的,那么就需要使用到 Gradle 提供的库依赖功能实现了。这里还是使用本节开始时的项目结构,比如其中的 game 工程依赖于 api 和 core 工程,而 api 又依赖于 core 工徎,其代码如下:
根工程中的 build.gradle 文件
subprojects {
apply plugin: 'java'
group = 'org.gradle.sample'
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
testCompile "junit:junit:4.12"
}
}
project(':api') {
dependencies {
compile project(':core')
}
}
project(':game') {
dependencies {
compile project(':core'), project(':api')
}
}
小结
在本章中我们介绍了 Gradle 构建的生命周期,然后实现了多工程的共享配置,最后分析了多工程的依赖关系。从而可以看到,在 Gradle 中实现多工程的构建是非常地简单,也是非常地灵活。