美文网首页
Gradle第11课:Gradle 实现多工程的编译打包

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

作者: 米饭超人 | 来源:发表于2018-08-28 11:09 被阅读290次

    需要准备

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

    相关文章

      网友评论

          本文标题:Gradle第11课:Gradle 实现多工程的编译打包

          本文链接:https://www.haomeiwen.com/subject/wjdfwftx.html