使用子專案和複合建置,了解建構 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 選用的設定檔
.   (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 子專案不屬於建置,而且你無法執行 task3,直到它被新增至 settings.gradle(.kts) 檔案。

若要將 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. 將建置新增至 Build

讓我們將外掛新增至我們的建置。首先,在 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,這些模組之間有依賴關係。

複合式 (include) 建置非常適合分離建置邏輯 (例如慣例外掛) 或測試系統 (例如修補程式庫)

下一步: 設定檔 >>