学习使用子项目和复合构建来构建 Gradle 项目的基本知识。

在本节中,您将:

  • 理解多项目构建

  • 理解复合构建

  • 向您的构建中添加一个子项目

  • 向您的构建中添加一个构建

步骤 0. 开始之前

  1. 您已在第 1 部分中初始化了 Java 应用程序。

  2. 您已在第 2 部分中理解了 Gradle 构建生命周期。

步骤 1. 关于多项目构建

通常,构建包含多个项目,例如共享库或将在您的生态系统中部署的独立应用程序。

在 Gradle 中,一个多项目构建包含:

  • settings.gradle(.kts) 文件,表示您的 Gradle 构建,包括所需的子项目,例如 include("app", "model", "service")

  • 每个子项目在其相应子目录中的 build.gradle(.kts) 文件和源代码

我们的构建目前由一个名为 authoring-tutorial 的根项目组成,该根项目有一个单独的 app 子项目。

.   (1)
├── app (2)
│   ... (3)
│   └── build.gradle.kts (4)
└── settings.gradle.kts  (5)
1 authoring-tutorial 根项目
2 app 子项目
3 app 源代码
4 app 构建脚本
5 可选的 settings 文件
.   (1)
├── app (2)
│   ... (3)
│   └── build.gradle (4)
└── settings.gradle  (5)
1 authoring-tutorial 根项目
2 app 子项目
3 app 源代码
4 app 构建脚本
5 可选的 settings 文件

步骤 2. 向构建中添加另一个子项目

假设我们的项目正在增长,并且需要一个自定义库才能运行。

让我们创建这个虚构的 lib。首先,创建一个 lib 文件夹

mkdir lib
cd lib

创建一个名为 build.gradle(.kts) 的文件,并向其中添加以下行:

lib/build.gradle.kts
plugins {
    id("java")
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    implementation("com.google.guava:guava:32.1.1-jre")
}

tasks.named<Test>("test") {
    useJUnitPlatform()
}

tasks.register("task3"){
    println("REGISTER TASK3: This is executed during the configuration phase")
}

tasks.named("task3"){
    println("NAMED TASK3: This is executed during the configuration phase")
    doFirst {
        println("NAMED TASK3 - doFirst: This is executed during the execution phase")
    }
    doLast {
        println("NAMED TASK3 - doLast: This is executed during the execution phase")
    }
}
lib/build.gradle
plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'com.google.guava:guava:32.1.1-jre'
}

test {
    useJUnitPlatform()
}

tasks.register('task3') {
    println('REGISTER TASK3: This is executed during the configuration phase')
}

tasks.named('task3') {
    println('NAMED TASK3: This is executed during the configuration phase')
    doFirst {
        println('NAMED TASK3 - doFirst: This is executed during the execution phase')
    }
    doLast {
        println('NAMED TASK3 - doLast: This is executed during the execution phase')
    }
}

您的项目应如下所示:

.
├── app
│   ...
│   └── build.gradle.kts
├── lib
│   └── build.gradle.kts
└── settings.gradle.kts
.
├── app
│   ...
│   └── build.gradle
├── lib
│   └── build.gradle
└── settings.gradle

让我们向 lib 子项目添加一些代码。创建一个新目录:

mkdir -p lib/src/main/java/com/gradle

在名为 CustomLib.java 的文件中创建一个名为 CustomLib 的 Java 类,其源代码如下:

lib/src/main/java/com/gradle/CustomLib.java
package com.gradle;

public class CustomLib {
    public static String identifier = "I'm a String from a lib.";
}

项目现在应具有以下文件和目录结构:

.
├── app
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── java
│               └── authoring
│                   └── tutorial
│                       └── App.java
├── lib
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── gradle
│                       └── CustomLib.java
└── settings.gradle.kts
.
├── app
│   ├── build.gradle
│   └── src
│       └── main
│           └── java
│               └── authoring
│                   └── tutorial
│                       └── App.java
├── lib
│   ├── build.gradle
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── gradle
│                       └── CustomLib.java
└── settings.gradle

然而,lib 子项目不属于构建,您将无法执行 task3,除非将其添加到 settings.gradle(.kts) 文件中。

要将 lib 添加到构建中,请相应地更新根目录中的 settings.gradle(.kts) 文件:

settings.gradle.kts
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0"
}

rootProject.name = "authoring-tutorial"

include("app")
include("lib") // Add lib to the build
settings.gradle
plugins {
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
}

rootProject.name = 'authoring-tutorial'

include('app')
include('lib') // Add lib to the build

让我们将 lib 子项目作为 app 的依赖项添加到 app/build.gradle(.kts) 中:

app/build.gradle.kts
dependencies {
    implementation(project(":lib")) // Add lib as an app dependency
}
app/build.gradle
dependencies {
    implementation(project(':lib')) // Add lib as an app dependency
}

更新 app 源代码,使其导入 lib

app/src/main/java/authoring/tutorial/App.java
package authoring.tutorial;

import com.gradle.CustomLib;

public class App {
    public String getGreeting() {
        return "CustomLib identifier is: " + CustomLib.identifier;
    }

    public static void main(String[] args) {
        System.out.println(new App().getGreeting());
    }
}

最后,让我们使用命令 ./gradlew run 运行 app

$ ./gradlew run

> Configure project :app

> Task :app:processResources NO-SOURCE
> Task :lib:compileJava
> Task :lib:processResources NO-SOURCE
> Task :lib:classes
> Task :lib:jar
> Task :app:compileJava
> Task :app:classes

> Task :app:run
CustomLib identifier is: I'm a String from a lib.

BUILD SUCCESSFUL in 11s
8 actionable tasks: 6 executed, 2 up-to-date

我们的根项目 authoring-tutorial 构建现在包含两个子项目:applibapp 依赖于 lib。您可以独立于 app 构建 lib。但是,要构建 app,Gradle 也会构建 lib

步骤 3. 理解复合构建

复合构建就是包含其他构建的构建。

复合构建允许您:

  • 将您的构建逻辑从项目构建中提取出来(并在子项目之间重用)

  • 组合通常独立开发的构建(例如插件和应用程序)

  • 将大型构建分解为更小、更独立的块

步骤 4. 向构建中添加构建

让我们向构建中添加一个插件。首先,在 gradle 目录中创建一个名为 license-plugin 的新目录:

cd gradle
mkdir license-plugin
cd license-plugin

gradle/license-plugin 目录中,运行 gradle init。确保您选择了 Gradle plugin 项目以及下面 init task 的其他选项:

$ gradle init --dsl kotlin --type kotlin-gradle-plugin --project-name license
$ gradle init --dsl groovy --type groovy-gradle-plugin --project-name license

对任何额外的提示选择默认值。

您的项目应如下所示:

.
├── app
│   ...
│   └── build.gradle.kts
├── lib
│   ...
│   └── build.gradle.kts
├── gradle
│    ├── ...
│    └── license-plugin
│        ├── settings.gradle.kts
│        └── plugin
│            ├── gradle
│            │   └── ....
│            ├── src
│            │   ├── functionalTest
│            │   │   └── ....
│            │   ├── main
│            │   │   └── kotlin
│            │   │       └── license
│            │   │           └── LicensePlugin.kt
│            │   └── test
│            │       └── ...
│            └── build.gradle.kts
│
└── settings.gradle.kts
.
├── app
│   ...
│   └── build.gradle
├── lib
│   ...
│   └── build.gradle
├── gradle
│    ├── ...
│    └── license-plugin
│        ├── settings.gradle
│        └── plugin
│            ├── gradle
│            │   └── ....
│            ├── src
│            │   ├── functionalTest
│            │   │   └── ....
│            │   ├── main
│            │   │   └── groovy
│            │   │       └── license
│            │   │           └── LicensePlugin.groovy
│            │   └── test
│            │       └── ...
│            └── build.gradle
│
└── settings.gradle

花时间查看 LicensePlugin.ktLicensePlugin.groovy 代码以及 gradle/license-plugin/settings.gradle(.kts) 文件。需要注意的是,这是一个完全独立的构建,有自己的 settings 文件和构建脚本。

gradle/license-plugin/settings.gradle.kts
rootProject.name = "license"
include("plugin")
gradle/license-plugin/settings.gradle
rootProject.name = 'license'
include('plugin')

要将我们的 license-plugin 构建添加到根项目中,请相应地更新根目录中的 settings.gradle(.kts) 文件:

settings.gradle.kts
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0"
}

rootProject.name = "authoring-tutorial"

include("app")
include("subproject")

includeBuild("gradle/license-plugin") // Add the new build
settings.gradle
plugins {
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
}

rootProject.name = 'running-tutorial-groovy'

include('app')
include('lib')

includeBuild('gradle/license-plugin')

您可以通过在根文件夹 authoring-tutorial 中运行 ./gradlew projects 来查看根项目的结构:

$ ./gradlew projects

------------------------------------------------------------
Root project 'authoring-tutorial'
------------------------------------------------------------

Root project 'authoring-tutorial'
+--- Project ':app'
\--- Project ':lib'

Included builds
\--- Included build ':license-plugin'

我们的根项目 authoring-tutorial 构建现在包含两个子项目:applib,以及另一个构建 license-plugin

在项目根目录中,运行:

  • ./gradlew build - 构建 applib

  • ./gradlew :app:build - 构建 applib

  • ./gradlew :lib:build - 仅构建 lib

  • ./gradlew :license-plugin:plugin:build - 仅构建 license-plugin

使用 Gradle 设计项目架构有多种方法。

多项目构建非常适合组织包含许多模块(例如 mobile-appweb-appapilibdocumentation)且模块之间存在依赖关系的项目。

复合(include)构建非常适合分离构建逻辑(即约定插件)或测试系统(即修补库)。

下一步: Settings 文件 >>