您可以在支援 Gradle 的 IDE 中開啟此範例。

為了讓您的軟體專案為成長做好準備,您可以將 Gradle 專案組織成多個子專案,以模組化您正在建置的軟體。在本指南中,您將學習如何以 Kotlin 應用程式為例,建構這樣的專案。但是,一般概念適用於您使用 Gradle 建置的任何軟體。您可以逐步按照指南從頭開始建立新專案,或使用上面的連結下載完整的範例專案。

您將建置的內容

您將建置一個 Kotlin 應用程式,其中包含一個應用程式和多個library專案。

您需要的內容

建立專案資料夾

Gradle 隨附一個內建的 task,稱為 init,它會在空的資料夾中初始化一個新的 Gradle 專案。 init task 使用(也是內建的) wrapper task 來建立 Gradle wrapper 腳本 gradlew

第一步是為新專案建立一個資料夾,並將目錄變更到該資料夾中。

$ mkdir demo
$ cd demo

執行 init task

從新專案目錄中,在終端機中使用以下命令執行 init task:gradle init。當出現提示時,選擇 1: application 專案類型和 2: Kotlin 作為實作語言。之後,選擇 2: Application and library project。接下來,您可以選擇用於撰寫建置腳本的 DSL - 1 : Kotlin2: Groovy。對於其他問題,按 Enter 鍵使用預設值。

輸出結果將如下所示

$ gradle init

Select type of build to generate:
  1: Application
  2: Library
  3: Gradle plugin
  4: Basic (build structure only)
Enter selection (default: Application) [1..4] 1

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

Project name (default: demo):

Enter target Java version (min: 7, default: 21):

Select application structure:
  1: Single application project
  2: Application and library project
Enter selection (default: Single application project) [1..2] 2

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

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4]

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]

BUILD SUCCESSFUL
1 actionable task: 1 executed

init task 會產生具有以下結構的新專案

├── 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.kotlin-application-conventions.gradle.kts
│               ├── buildlogic.kotlin-common-conventions.gradle.kts
│               └── buildlogic.kotlin-library-conventions.gradle.kts
├── app
│   ├── build.gradle.kts (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── app
│       │               ├── App.java
│       │               └── MessageUtils.kt
│       └── test (9)
│           └── java
│               └── demo
│                   └── app
│                       └── MessageUtilsTest.kt
├── list
│   ├── build.gradle.kts (7)
│   └── src
│       ├── main (8)
│       │   └── java
│       │       └── demo
│       │           └── list
│       │               └── LinkedList.kt
│       └── test (9)
│           └── java
│               └── demo
│                   └── list
│                       └── LinkedListTest.kt
└── utilities
    ├── build.gradle.kts (7)
    └── src
        └── main (8)
            └── java
                └── demo
                    └── utilities
                        ├── JoinUtils.kt
                        ├── SplitUtils.kt
                        └── StringUtils.kt
├── 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.kotlin-application-conventions.gradle
│               ├── buildlogic.kotlin-common-conventions.gradle
│               └── buildlogic.kotlin-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 為 wrapper 檔案產生的資料夾
2 產生的版本目錄
3 Gradle wrapper 啟動腳本
4 Settings 檔案,用於定義建置名稱和子專案
5 buildSrc 的 Build 腳本,用於配置建置邏輯的相依性
6 以 Groovy 或 Kotlin DSL 撰寫的慣例外掛程式的來源資料夾
7 三個子專案(applistutilities)的 Build 腳本
8 每個子專案中的 Kotlin 來源資料夾
9 子專案中的 Kotlin 測試來源資料夾

您現在已設定好專案,以建置模組化為多個子專案的 Kotlin 應用程式。

檢閱專案檔案

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.kotlin-common-conventions.gradle.kts
plugins {
    id("org.jetbrains.kotlin.jvm") (1)
}

repositories {
    mavenCentral() (2)
}

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

    testImplementation("org.junit.jupiter:junit-jupiter:5.11.3") (4)

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

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

repositories {
    mavenCentral() (2)
}

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

    testImplementation 'org.junit.jupiter:junit-jupiter:5.11.3' (4)

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

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

kotlin-common-conventions 定義了一些應由我們所有 Kotlin 專案共享的配置,無論它們代表的是 library 還是實際的應用程式。首先,我們套用 Kotlin Gradle 外掛程式 (1),以具備建置 Kotlin 專案的所有功能。然後,我們宣告一個儲存庫 — mavenCentral() — 作為外部相依性的來源 (2)、定義相依性約束 (3) 以及所有子專案共享的標準相依性,並設定 JUnit 5 作為測試框架 (4…​)。其他共享設定(例如編譯器標誌或 JVM 版本相容性)也可以在此處設定。

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

kotlin-library-conventionskotlin-application-conventions 都套用了 kotlin-common-conventions 外掛程式 (1),以便 library 和應用程式專案都共享在那裡執行的配置。接下來,它們分別套用 java-libraryapplication 外掛程式 (2),從而將我們的通用配置邏輯與 library 或應用程式的特定細節結合起來。雖然在此範例中沒有更精細的配置,但 library 或應用程式專案特定的建置配置可以放入其中一個慣例外掛程式腳本中。

讓我們看看子專案中的 build.gradle(.kts) 檔案。

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

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

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

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

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

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

dependencies {
    api project(':list')
}

查看建置腳本,我們可以看到它們最多包含三個區塊

  • 每個建置腳本都應具有 plugins {} 區塊以套用外掛程式。在結構良好的建置中,它可能只套用一個慣例外掛程式,如本範例所示。然後,慣例外掛程式將負責套用和配置核心 Gradle 外掛程式(例如 applicationjava-library)、其他慣例外掛程式或來自外掛程式入口網站的社群外掛程式。

  • 其次,如果專案具有相依性,則應新增 dependencies {} 區塊。相依性可以是外部的,例如我們在 kotlin-common-conventions 中新增的 JUnit 相依性,也可以指向其他本機子專案。為此,使用 project(…​) 標記法。在我們的範例中,utilities library 需要 list library。而 app 使用 utilities library。如果本機專案彼此相依,Gradle 會負責在需要時(且僅在需要時)建置相依專案。若要了解更多資訊,請查看有關 Gradle 中的相依性管理 的文件。

  • 第三,外掛程式可能有一個或多個配置區塊。這些區塊應僅在直接在建置腳本中使用,如果它們配置了某個專案特定的內容。否則,這些配置也應屬於慣例外掛程式。在本範例中,我們使用 application {} 區塊,這是 application 外掛程式特有的,以在我們的 app 專案中將 mainClass 設定為 demo.app.App (1)

我們擁有的最後一個建置檔案是 build.gradle(.kts) 檔案,位於 buildSrc 中。

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

repositories {
    gradlePluginPortal() (2)
}

dependencies {
    implementation(libs.kotlin.gradle.plugin)
}
buildSrc/build.gradle
plugins {
    id 'groovy-gradle-plugin' (1)
}

repositories {
    gradlePluginPortal() (2)
}

dependencies {
    implementation libs.kotlin.gradle.plugin
}

此檔案正在為建置慣例外掛程式本身做準備。透過套用外掛程式開發的外掛程式之一 — groovy-gradle-pluginkotlin-dsl(1),我們啟用了在 buildSrc 中將慣例外掛程式撰寫為建置檔案的支援。這些是我們已經在上面檢查過的慣例外掛程式。此外,我們新增 Gradle 的外掛程式入口網站作為儲存庫 (2),這讓我們可以存取社群外掛程式。若要使用外掛程式,需要在 dependencies {} 區塊中將其宣告為相依性。

除了 Gradle 建置檔案之外,您還可以在對應的資料夾中找到範例 Kotlin 原始碼和測試原始碼。隨意修改這些產生的原始碼和測試,以探索在執行如下所述的建置時 Gradle 如何對變更做出反應。

執行測試

您可以使用 ./gradlew check 來執行所有子專案中的所有測試。當您使用純 task 名稱(例如 check)呼叫 Gradle 時,將會為提供該 task 的所有子專案執行該 task。若要僅針對特定子專案,您可以使用 task 的完整路徑。例如,:app:check 將僅執行 app 專案的測試。但是,在本範例中,其他子專案仍將被編譯,因為 app 宣告了對它們的相依性。

$ ./gradlew check

BUILD SUCCESSFUL
9 actionable tasks: 9 executed

如果所有測試都成功通過,Gradle 不會在主控台中列印更多輸出。您可以在 <子專案>/build/reports 資料夾中找到測試報告。隨意變更一些範例程式碼或測試,然後重新執行 check,以查看測試失敗時會發生什麼情況。

執行應用程式

由於有了 application 外掛程式,您可以直接從命令列執行應用程式。 run task 會告知 Gradle 執行在指派給 mainClass 屬性的類別中的 main 方法。

$ ./gradlew run

> Task :app:run
Hello world!

BUILD SUCCESSFUL
2 actionable tasks: 2 executed
第一次執行 wrapper 腳本 gradlew 時,可能會有一段延遲,因為該版本的 gradle 會被下載並在本機儲存在您的 ~/.gradle/wrapper/dists 資料夾中。

捆綁應用程式

application 外掛程式也會為您捆綁應用程式及其所有相依性。封存檔也將包含一個腳本,用於使用單一命令啟動應用程式。

$ ./gradlew build

BUILD SUCCESSFUL in 0s
8 actionable tasks: 8 executed

如果您執行如上所示的完整建置,Gradle 將會為您產生兩種格式的封存檔:app/build/distributions/app.tarapp/build/distributions/app.zip

發布 Build Scan

若要深入了解您的建置在幕後執行的操作,最好的方法是發布 build scan。若要執行此操作,只需使用 --scan 旗標執行 Gradle。

$ ./gradlew build --scan

BUILD SUCCESSFUL in 0s
8 actionable tasks: 8 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

按一下連結並探索執行了哪些 task、下載了哪些相依性以及更多詳細資訊!

摘要

就這樣!您現在已成功使用 Gradle 配置和建置了 Kotlin 應用程式專案。您已學習如何

  • 初始化一個產生 Kotlin 應用程式的專案

  • 透過結合多個子專案來建立模組化軟體專案

  • 使用 buildSrc 中的慣例外掛程式在子專案之間共享建置配置邏輯

  • 在所有子專案中執行相似名稱的 task

  • 在特定子專案中執行 task

  • 建置、捆綁和執行應用程式

下一步

當您的專案成長時,您可能會對如何配置 JVM 專案、建構多專案建置和相依性管理的更多詳細資訊感興趣