Gradle第11课:Gradle 实现多工程的编译打包

需要准备

  • 一个熟悉的 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 中实现多工程的构建是非常地简单,也是非常地灵活。

    原文作者:米饭超人
    原文地址: https://www.jianshu.com/p/81f00bc1448e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞