您可以在 IDE 中使用 IntelliJ 原生导入器Eclipse Buildship 打开此示例。

为了让您的软件项目为增长做好准备,您可以将 Gradle 项目组织成多个子项目,以模块化您正在构建的软件。在本指南中,您将学习如何以 Groovy 应用程序为例构建这样的项目。但是,这些通用概念适用于您使用 Gradle 构建的任何软件。您可以按照本指南一步一步地从头开始创建一个新项目,也可以使用上面的链接下载完整的示例项目。

您将构建什么

您将构建一个 Groovy 应用程序,它包含一个应用程序和多个项目。

您需要什么

创建项目文件夹

Gradle 自带一个名为 init 的内置任务,用于在空文件夹中初始化一个新的 Gradle 项目。init 任务使用(也是内置的)wrapper 任务来创建一个 Gradle 包装器脚本,gradlew

第一步是为新项目创建一个文件夹,并进入该文件夹。

$ mkdir demo
$ cd demo

运行 init 任务

在新项目目录中,使用以下命令在终端中运行 init 任务:gradle init。当提示时,选择 1: application 项目类型和 3: Groovy 作为实现语言。之后,选择 2: Add library projects。接下来,您可以选择用于编写构建脚本的 DSL - 1 : Groovy2: Kotlin。对于其他问题,按回车键使用默认值。

输出将如下所示

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 1

Split functionality across multiple subprojects?:
   1: no - only one application project
   2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Project name (default: demo):
Source package (default: demo):


BUILD SUCCESSFUL
2 actionable tasks: 2 executed

init 任务使用以下结构生成新项目

├── gradle (1)
│   ├── libs.versions.toml (2)
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle.kts (4)
├── buildSrc
│   ├── build.gradle.kts (5)
│   ├── settings.gradle.kts (5)
│   └── src
│       └── main
│           └── kotlin (6)
│               ├── buildlogic.groovy-application-conventions.gradle.kts
│               ├── buildlogic.groovy-common-conventions.gradle.kts
│               └── buildlogic.groovy-library-conventions.gradle.kts
├── app
│   ├── build.gradle.kts (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── app
│       │               ├── App.java
│       │               └── MessageUtils.groovy
│       └── test (9)
│           └── java
│               └── demo
│                   └── app
│                       └── MessageUtilsTest.groovy
├── list
│   ├── build.gradle.kts (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── list
│       │               └── LinkedList.groovy
│       └── test (9)
│           └── java
│               └── demo
│                   └── list
│                       └── LinkedListTest.groovy
└── utilities
    ├── build.gradle.kts (7)
    └── src
        └── main (8)
            └── java
                └── demo
                    └── utilities
                        ├── JoinUtils.groovy
                        ├── SplitUtils.groovy
                        └── StringUtils.groovy
├── gradle (1)
│   ├── libs.versions.toml (2)
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew (3)
├── gradlew.bat (3)
├── settings.gradle (4)
├── buildSrc
│   ├── build.gradle (5)
│   ├── settings.gradle (5)
│   └── src
│       └── main
│           └── groovy (6)
│               ├── buildlogic.groovy-application-conventions.gradle
│               ├── buildlogic.groovy-common-conventions.gradle
│               └── buildlogic.groovy-library-conventions.gradle
├── app
│   ├── build.gradle (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── app
│       │               ├── App.java
│       │               └── MessageUtils.java
│       └── test (9)
│           └── java
│               └── demo
│                   └── app
│                       └── MessageUtilsTest.java
├── list
│   ├── build.gradle (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── list
│       │               └── LinkedList.java
│       └── test (9)
│           └── java
│               └── demo
│                   └── list
│                       └── LinkedListTest.java
└── utilities
    ├── build.gradle (7)
    └── src
        └── main (8)
            └── java
                └── demo
                    └── utilities
                        ├── JoinUtils.java
                        ├── SplitUtils.java
                        └── StringUtils.java
1 为包装器文件生成的文件夹
2 生成的版本目录
3 Gradle 包装器启动脚本
4 设置文件,用于定义构建名称和子项目
5 buildSrc 的构建脚本,用于配置构建逻辑的依赖项
6 用 Groovy 或 Kotlin DSL 编写的约定插件的源文件夹
7 三个子项目的构建脚本 - applistutilities
8 每个子项目中的 Groovy 源文件夹
9 子项目中的 Groovy 测试源文件夹

您现在已经设置好项目,可以构建一个模块化为多个子项目的 Groovy 应用程序。

查看项目文件

settings.gradle(.kts) 文件有两行有趣的代码

settings.gradle.kts
rootProject.name = "demo"
include("app", "list", "utilities")
settings.gradle
rootProject.name = 'demo'
include('app', 'list', 'utilities')
  • rootProject.name 为构建分配一个名称,这将覆盖将构建命名为其所在目录的默认行为。建议设置一个固定名称,因为如果项目是共享的,例如作为 Git 存储库的根目录,文件夹可能会更改。

  • include("app", "list", "utilities") 定义构建包含对应文件夹中的三个子项目。可以通过扩展列表或添加更多 include(…​) 语句来添加更多子项目。

由于我们的构建包含多个子项目,我们希望在它们之间共享构建逻辑和配置。为此,我们利用所谓的约定插件,这些插件位于 buildSrc 文件夹中。buildSrc 中的约定插件是利用 Gradle 的插件系统来编写可重用构建配置片段的简便方法。

在这个示例中,我们可以找到三个这样的约定插件,它们是基于彼此的

buildSrc/src/main/kotlin/buildlogic.groovy-common-conventions.gradle.kts
plugins {
    groovy (1)
}

repositories {
    mavenCentral() (2)
}

dependencies {
    constraints {
        implementation("org.apache.commons:commons-text:1.11.0") (3)

        implementation("org.codehaus.groovy:groovy-all:3.0.19")
    }

    implementation("org.codehaus.groovy:groovy-all") (4)

    testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") (5)

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.named<Test>("test") {
    useJUnitPlatform() (6)
}
buildSrc/src/main/groovy/buildlogic.groovy-common-conventions.gradle
plugins {
    id 'groovy' (1)
}

repositories {
    mavenCentral() (2)
}

dependencies {
    constraints {
        implementation 'org.apache.commons:commons-text:1.11.0' (3)

        implementation 'org.codehaus.groovy:groovy-all:3.0.19'
    }

    implementation 'org.codehaus.groovy:groovy-all' (4)

    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' (5)

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
    useJUnitPlatform() (6)
}

groovy-common-conventions 定义了一些所有 Groovy 项目应该共享的配置,无论它们是库还是实际的应用程序。首先,我们应用 Groovy 插件 (1) 以使所有用于构建 Groovy 项目的功能可用。然后,我们声明一个存储库 - mavenCentral() - 作为外部依赖项的来源 (2),定义依赖项约束 (3) 以及所有子项目共享的标准依赖项,并将 JUnit 5 设置为测试框架 (4…​)。其他共享设置,如编译器标志或 JVM 版本兼容性,也可以在这里设置。

buildSrc/src/main/kotlin/buildlogic.groovy-library-conventions.gradle.kts
plugins {
    id("buildlogic.groovy-common-conventions") (1)
    `java-library` (2)
}
buildSrc/src/main/groovy/buildlogic.groovy-library-conventions.gradle
plugins {
    id 'buildlogic.groovy-common-conventions' (1)
    id 'java-library' (2)
}
buildSrc/src/main/kotlin/buildlogic.groovy-application-conventions.gradle.kts
plugins {
    id("buildlogic.groovy-common-conventions") (1)
    application (2)
}
buildSrc/src/main/groovy/buildlogic.groovy-application-conventions.gradle
plugins {
    id 'buildlogic.groovy-common-conventions' (1)
    id 'application' (2)
}

groovy-library-conventionsgroovy-application-conventions 都应用了 groovy-common-conventions 插件 (1),以便在那里执行的配置由库和应用程序项目共享。接下来,它们分别应用 java-libraryapplication 插件 (2),从而将我们的通用配置逻辑与库或应用程序的具体内容相结合。虽然在这个例子中没有更细粒度的配置,但库或应用程序项目特定的构建配置可以进入这些约定插件脚本中的一个。

让我们看一下子项目中的 build.gradle(.kts) 文件。

app/build.gradle.kts
plugins {
    id("buildlogic.groovy-application-conventions")
}

dependencies {
    implementation("org.apache.commons:commons-text")
    implementation(project(":utilities"))
}

application {
    mainClass = "demo.app.App" (1)
}
app/build.gradle
plugins {
    id 'buildlogic.groovy-application-conventions'
}

dependencies {
    implementation 'org.apache.commons:commons-text'
    implementation project(':utilities')
}

application {
    mainClass = 'demo.app.App' (1)
}
list/build.gradle.kts
plugins {
    id("buildlogic.groovy-library-conventions")
}
list/build.gradle
plugins {
    id 'buildlogic.groovy-library-conventions'
}
utilities/build.gradle.kts
plugins {
    id("buildlogic.groovy-library-conventions")
}

dependencies {
    api(project(":list"))
}
utilities/build.gradle
plugins {
    id 'buildlogic.groovy-library-conventions'
}

dependencies {
    api project(':list')
}

查看构建脚本,我们可以看到它们包含最多三个块

  • 每个构建脚本都应该有一个 plugins {} 块来应用插件。在一个结构良好的构建中,它可能只应用一个约定插件,如本例所示。约定插件将负责应用和配置核心 Gradle 插件(如 applicationjava-library)其他约定插件或来自插件门户的社区插件。

  • 其次,如果项目有依赖项,则应添加一个 dependencies {} 块。依赖项可以是外部的,例如我们在 groovy-common-conventions 中添加的 JUnit 依赖项,也可以指向其他本地子项目。为此,使用 project(…​) 符号。在我们的示例中,utilities 库需要 list 库。而 app 使用了 utilities 库。如果本地项目相互依赖,Gradle 会在需要时(且仅在需要时)构建依赖项目。要了解更多信息,请查看有关 Gradle 中的依赖项管理 的文档。

  • 第三,可能存在一个或多个插件配置块。这些仅应在构建脚本中直接使用,如果它们为一个项目配置了特定内容。否则,此类配置也属于约定插件。在本例中,我们使用 application {} 块,它是 application 插件特有的,在我们的 app 项目中将 mainClass 设置为 demo.app.App (1)

我们最后一个构建文件是 buildSrc 中的 build.gradle(.kts) 文件。

buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl` (1)
}

repositories {
    gradlePluginPortal() (2)
}
buildSrc/build.gradle
plugins {
    id 'groovy-gradle-plugin' (1)
}

repositories {
    gradlePluginPortal() (2)
}

此文件为构建约定插件本身奠定了基础。通过应用其中一个插件开发插件——groovy-gradle-pluginkotlin-dsl——**(1)**,我们启用了将约定插件作为 buildSrc 中的构建文件编写支持。这些就是我们上面已经检查过的约定插件。此外,我们将 Gradle 的插件门户添加为存储库**(2)**,这使我们能够访问社区插件。要使用插件,需要在 dependencies {} 块中将其声明为依赖项。

除了 Gradle 构建文件外,您还可以在相应的文件夹中找到示例 Groovy 源代码和测试源代码。随意修改这些生成的源代码和测试,以探索 Gradle 在运行构建时如何对更改做出反应,如下一节所述。

运行测试

您可以使用 ./gradlew check 来执行所有子项目中的所有测试。当您使用纯任务名称(如 check)调用 Gradle 时,该任务将在提供该任务的所有子项目中执行。要仅针对特定子项目,可以使用该任务的完整路径。例如,:app:check 将仅执行 app 项目的测试。但是,在本例中,其他子项目仍将被编译,因为 app 向它们声明了依赖项。

$ ./gradlew check

BUILD SUCCESSFUL
9 actionable tasks: 9 executed

如果所有测试都成功通过,Gradle 不会在控制台中打印更多输出。您可以在 <subproject>/build/reports 文件夹中找到测试报告。随意更改一些示例代码或测试,然后重新运行 check 以查看测试失败时会发生什么。

运行应用程序

由于 application 插件,您可以直接从命令行运行应用程序。run 任务告诉 Gradle 执行分配给 mainClass 属性的类中的 main 方法。

$ ./gradlew run

> Task :app:run
Hello world!

BUILD SUCCESSFUL
2 actionable tasks: 2 executed
您第一次运行包装器脚本 gradlew 时,可能会延迟一段时间,因为该版本的 gradle 将被下载并存储在您的 ~/.gradle/wrapper/dists 文件夹中。

捆绑应用程序

application 插件还会将应用程序及其所有依赖项捆绑在一起。该存档还将包含一个脚本,用于使用单个命令启动应用程序。

$ ./gradlew build

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed

如果您运行如上所示的完整构建,Gradle 将为您生成两种格式的存档:app/build/distributions/app.tarapp/build/distributions/app.zip

发布构建扫描

了解构建在幕后执行的操作的最佳方式是发布一个构建扫描。为此,只需使用--scan标志运行 Gradle。

$ ./gradlew build --scan

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service.
Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/5u4w3gxeurtd2

点击链接并探索哪些任务被执行,哪些依赖项被下载以及更多详细信息!

摘要

就是这样!您现在已成功配置并构建了使用 Gradle 的 Groovy 应用程序项目。您已了解如何

  • 初始化一个生成 Groovy 应用程序的项目

  • 通过组合多个子项目来创建模块化软件项目

  • 使用buildSrc中的约定插件在子项目之间共享构建配置逻辑

  • 在所有子项目中运行类似名称的任务

  • 在特定子项目中运行任务

  • 构建、捆绑和运行应用程序

下一步

当您的项目发展壮大时,您可能对如何配置 JVM 项目、构建多项目结构以及依赖项管理的更多详细信息感兴趣