【Gradle 多模块系列1】 多项目构建子项目创建

gradle多项目构建和子项目的添加管理

执行多项目构建

只有最小的项目才会有一个构建文件和源代码树,除非它恰好是一个庞大的、单块式的应用程序。将项目分割成较小、相互依赖的模块通常更容易理解和理解。然而,“相互依赖”这个词很重要,这就是为什么通常希望通过单个构建将这些模块链接在一起。

Gradle通过多项目构建支持这种情况。

项目路径

项目路径的模式如下:它以一个可选的冒号开始,表示根项目

根项目:是路径中唯一不是通过名称指定的项目。**项目路径的其余部分是由冒号分隔的项目名称序列,**其中下一个项目是前一个项目的子项目。您可以在运行gradle projects命令时看到项目路径,如“确定项目结构”部分所示。

在大多数情况下,项目路径反映了文件系统布局,但也有例外情况。最显著的例子是组合构建(composite builds)。还请参阅如何使用include声明子项目之间的依赖项,并使用includeBuild创建组合构建。

确定项目结构

确定项目结构,可以使用gradle projects命令。例如,让我们使用具有以下结构的多项目构建:

> gradle -q projects

------------------------------------------------------------
Root project 'multiproject'
------------------------------------------------------------

Root project 'multiproject'
+--- Project ':api'
+--- Project ':services'
|    +--- Project ':services:shared'
|    \--- Project ':services:webservice'
\--- Project ':shared'

查看项目的任务列表,请运行gradle <project-path>:tasks。例如,尝试运行gradle :api:tasks。从用户的角度来看,多项目构建仍然是可运行的任务集合。不同之处在于,您可能想要控制执行哪个项目的任务。

下面的几节将介绍在多项目构建中执行任务的两种选择。

执行任务的两种选择

通过名称执行任务

命令gradle test将在任何具有该任务的子项目中执行test任务,相对于当前工作目录。如果您从根项目目录运行该命令,将在api、shared、services:shared和services:webservice中运行test任务。如果您从services项目目录运行该命令,只会在services:shared和services:webservice中执行该任务。

Gradle行为背后的基本规则是:执行所有具有此名称的任务的子项目。只有在遍历的所有子项目中都找不到这样的任务时才会出现错误。

某些任务选择器(如help或dependencies)只会在它们所调用的项目上运行任务,而不会在所有子项目上运行。这样做的主要原因是,这些任务打印出的信息如果结合了所有项目的信息将很难处理。

Gradle沿着层次结构向下查找具有给定名称的任务并执行它们,从当前目录开始。一个非常重要的注意事项是,Gradle始终评估多项目构建的每个项目,并创建所有现有的任务对象。然后,根据任务名称参数和当前目录,Gradle过滤应该执行的任务。由于Gradle的跨项目配置,必须在执行任何任务之前对每个项目进行评估。

当使用Gradle Wrapper时,通过在子项目的目录中运行Gradle来为特定的子项目执行任务的方式效果不好,因为如果您不在项目根目录中,必须指定包装器脚本的路径。例如,如果要为webservice子项目运行build任务,并且您在webservice子项目的目录中,您将需要运行../../gradlew build。下一节将展示如何可以直接从项目的根目录实现这一点。

通过完全限定名称执行任务

您可以使用任务的完全限定名称来在特定的子项目中执行特定的任务。例如:gradle :services:webservice:build将运行webservice子项目的build任务。任务的完全限定名称只是其项目路径加上任务名称。

此方法适用于任何任务,因此如果您想知道特定子项目中有哪些任务,请使用tasks任务,例如gradle :services:webservice:tasks

无论您使用哪种技术来执行任务,Gradle都会负责构建目标所依赖的任何子项目。您不必担心项目之间的相互依赖关系。如果您对如何配置这一点感兴趣,可以阅读有关编写多项目构建的更多信息,请参阅用户手册。

多项目构建和测试

Java插件的build任务通常用于编译、测试和执行代码样式检查(如果使用CodeQuality插件)单个项目

在多项目构建中,您可能经常希望在一系列项目中执行所有这些任务。buildNeededbuildDependents任务可以帮助实现这一点。

在这个例子中,:services:person-service项目依赖于:api和:shared两个项目。:api项目也依赖于:shared项目。

假设您正在工作的只是一个单独的项目,即:api项目。您已经进行了一些更改,但自从执行clean操作以来,还没有完整地构建整个项目。您希望构建任何必要的支持JAR文件,但仅在您更改过的项目上执行代码质量和单元测试。build任务可以实现这一点。

示例1. 构建和测试单个项目

gradle :api:build的输出:

> gradle :api:build
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build

BUILD SUCCESSFUL in 0s

如果刚刚从版本控制系统中获取了包含其他项目中对:api项目的更改的最新版本,您可能不仅想要构建所有您所依赖的项目,还要对它们进行测试。buildNeeded任务也会测试测试运行时配置的项目依赖项的项目

示例2. 构建和测试所依赖的项目

gradle :api:buildNeeded的输出:

> gradle :api:buildNeeded
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :shared:assemble
> Task :shared:compileTestJava
> Task :shared:processTestResources
> Task :shared:testClasses
> Task :shared:test
> Task :shared:check
> Task :shared:build
> Task :shared:buildNeeded
> Task :api:buildNeeded

BUILD SUCCESSFUL in 0s

您还可能希望重构某些在其他项目中使用的:api项目的部分。如果进行了此类更改,仅测试:api项目是不够的,还需要测试所有依赖于:api项目的项目。buildDependents任务也会测试在指定项目上具有项目依赖关系(在testRuntime配置中)的所有项目。

示例3. 构建和测试依赖的项目

gradle :api:buildDependents的输出:

> gradle :api:buildDependents
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :services:person-service:compileJava
> Task :services:person-service:processResources
> Task :services:person-service:classes
> Task :services:person-service:jar
> Task :services:person-service:assemble
> Task :services:person-service:compileTestJava
> Task :services:person-service:processTestResources
> Task :services:person-service:testClasses
> Task :services:person-service:test
> Task :services:person-service:check
> Task :services:person-service:build
> Task :services:person-service:buildDependents
> Task :api:buildDependents

BUILD SUCCESSFUL in 0s

最后,您可能希望构建和测试所有项目中的所有内容。在根项目文件夹中运行的任何任务都将导致相同名称的任务在所有子项目中运行。因此,您只需运行gradle build即可构建和测试所有项目。

如何使用Gradle多项目目录

如果您使用Gradle构建规模较大的软件,有两种基本的结构化机制可供选择。首先,本章将介绍如何使用Gradle多项目来组织您的软件项目。在本文档中,我们将其视为一个内部结构化的单个软件组件。其次,您可以将您的软件视为由多个软件组件组成的软件产品,每个组件由一个单独的Gradle构建表示。这一点在关于使用Gradle构建软件产品的章节中有详细描述。

创建多项目构建

在Gradle中,多项目构建由一个根项目一个或多个子项目组成。

基本的多项目构建包含一个根项目和一个单独的子项目。下面是一个包含一个名为app的子项目的多项目构建结构:

例1. 基本的多项目构建

Project layout
.
├── app
│   ...
│   └── build.gradle
└── settings.gradle

这是开始任何Gradle项目的推荐项目结构。build init插件还会生成符合此结构的骨架项目 - 一个带有单个子项目的根项目。

请注意,根项目没有Gradle构建文件,只有一个定义要包括的子项目的设置文件。

设置文件(settings.gradle)中的内容如下:

rootProject.name = 'basic-multiproject'
include 'app'

在这种情况下,Gradle将在app目录中查找构建文件。

我们可以通过运行gradle projects命令来查看多项目构建的结构。

> gradle -q projects

------------------------------------------------------------
Root project 'basic-multiproject'
------------------------------------------------------------

Root project 'basic-multiproject'
\--- Project ':app'

要查看项目的任务列表,请运行gradle <project-path>:tasks。例如,尝试运行gradle :app:tasks

假设app子项目是一个应用程序,应用了**application插件**并配置了主类。

app/build.gradle文件中的内容如下:

plugins {
    id 'application'
}

application {
    mainClass = 'com.example.Hello'
}

app/src/main/java/com/example/Hello.java文件中的内容如下:

package com.example;

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

然后,我们可以通过执行应用程序插件的run任务来运行该应用程序。

> gradle -q run
Hello, world!

这就是创建基本多项目构建的简单方法。

添加子项目

假设我们想在之前创建的项目中添加另一个名为lib的子项目。我们只需要在根setting文件中添加另一个include语句

设置文件(settings.gradle)中的内容如下:

rootProject.name = 'basic-multiproject'
include 'app'
include 'lib'

然后,Gradle将在项目的lib/子目录中查找新子项目的构建文件。

例2. 包含两个子项目的多项目构建

Project layout
.
├── app
│   ...
│   └── build.gradle
├── lib
│   ...
│   └── build.gradle
└── settings.gradle

接下来,我们将探讨如何在子项目之间共享构建逻辑以及子项目如何相互依赖。

命名建议

随着项目的增长,命名和一致性变得越来越重要。为了保持构建的可维护性,我们建议以下做法:

  • 保留子项目的默认项目名称:可以在设置文件中配置自定义项目名称。然而,对于开发人员来说,跟踪哪个项目属于哪个文件夹是一个不必要的额外工作。

  • 对所有项目名称使用短横线格式:短横线格式是指所有字母小写,单词之间用短横线(-)分隔的格式(例如kebab-case-formatting)。这已经成为许多大型项目的事实标准模式。此外,Gradle支持缩写短横线格式的名称。

  • 在setting.gradle文件中定义根项目名称rootProject.name有效地为整个构建分配一个名称,该名称在构建扫描等报告中使用。如果未设置根项目名称,则名称将是容器目录名称,可能不稳定(即您可以将项目检出到任何目录)。

    如果未设置根项目名称,并且它被检出到文件系统的根目录(例如/C:\),则名称将被随机生成。

格式**:短横线格式是指所有字母小写,单词之间用短横线(-)分隔的格式(例如kebab-case-formatting)。这已经成为许多大型项目的事实标准模式。此外,Gradle支持缩写短横线格式的名称。

  • 在setting.gradle文件中定义根项目名称rootProject.name有效地为整个构建分配一个名称,该名称在构建扫描等报告中使用。如果未设置根项目名称,则名称将是容器目录名称,可能不稳定(即您可以将项目检出到任何目录)。

    如果未设置根项目名称,并且它被检出到文件系统的根目录(例如/C:\),则名称将被随机生成。

参考链接

小军李:【Gradle jvm插件系列1】 Java Application插件权威详解

小军李:【Gradle jvm插件系列2】 Java Library插件用法示例权威详解

小军李:【Gradle jvm插件系列3】 Java platform平台插件权威详解

小军李:【Gradle jvm插件系列4】 scala插件权威详解

小军李:【gradle多模块系列1】多项目构建和子项目的添加管理

小军李:【Gradle多模块系列2】在子项目之间声明依赖关系和共享构建逻辑示例详解

小军李:【Gradle 多模块系列3】如何开发自定义Gradle插件

小军李:【Gradle多模块系列4】JVM项目的依赖管理

gradlew gradle常用命令选项用法适用场景用法示例词典详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值