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

在本部分中,您将

  • 了解多项目构建

  • 了解复合构建

  • 向构建添加子项目

  • 向构建添加构建

步骤 0. 开始之前

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

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

步骤 1. 关于多项目构建

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

在 Gradle 中,多项目构建包括

  • 表示您的 Gradle 构建的文件 settings.gradle(.kts),包括必需的子项目,例如 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 可选的设置文件
.   (1)
├── app (2)
│   ... (3)
│   └── build.gradle (4)
└── settings.gradle  (5)
1 authoring-tutorial 根项目
2 app 子项目
3 app 源代码
4 app 构建脚本
5 可选的设置文件

步骤 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 子项目不属于该构建,并且在将其添加到 settings.gradle(.kts) 文件之前,您将无法执行 task3

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

settings.gradle.kts
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.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.7.0'
}

rootProject.name = 'authoring-tutorial'

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

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

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 任务的其他选项

$ 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) 文件。请务必注意,这是一个完全独立的构建,具有自己的设置文件和构建脚本

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.7.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.7.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,这些模块之间存在依赖关系。

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

下一步: 设置文件 >>