因為後續會頻繁使用 Gradle,在此稍微花一個章節來詳細介紹一下 Gradle。特別感謝我的朋友 Clarke 在這個章節中給予全面的指導與建議:
Gradle 是 Java 生態系統中非常強大的自動化建構工具,類似於 Java 的 Makefile。它可以幫助開發者在專案開發過程中自動化處理各種繁瑣的任務,例如編譯、測試、檢查程式碼、生成文件、清理專案或壓縮檔案,甚至包括部署到伺服器、發布版本、重啟服務,或是發送通知郵件。這些操作都可以透過 Gradle 的 Script 自動完成,讓開發流程更加順暢與高效。
Gradle 擁有以下幾個顯著的特點:
從 2011 年起,許多 Groovy 和 Java 開發者開始使用 Gradle 作為主要的建構工具。雖然早期版本(1.0 之前)有些 Bug 和性能問題,但隨著不斷優化,這些問題已經得到解決。Gradle 現已成為 Java 開發的重要工具之一,受到開發者廣泛的喜愛。
特別值得一提的是,Google 在 2013 年將 Gradle 整合到 Android SDK 建構系統中,這大大鞏固了其在 Java 世界的地位。如今,Gradle 幾乎是 Java 專案建置的標準工具之一。
除了 Android 開發之外,Gradle 在其他領域也被廣泛應用:
隨著雲端架構和微服務設計的普及,Gradle 作為一個靈活且高效的建構工具,正在成為越來越多開發者的首選。其跨平台、易用性和高效能使得 Gradle 在現代專案開發中的應用日益廣泛。對於希望構建雲原生應用的開發者,熟練掌握 Gradle 不僅能提升開發速度,也能為專案的自動化、擴展性和持續交付提供更好的支持。
Quarkus 專案的 Gradle 文件中,兩個重要的概念是 任務(Tasks) 和 依賴(Dependencies)。
Gradle 的任務代表了一個獨立的工作單位,例如編譯程式碼、生成 JAR 檔案、產生 Javadoc 或將檔案發佈到Repository。每個任務可以透過 Gradle 的Plugin或是你自己的建置腳本來定義並執行。
以一個簡單的 Gradle 專案為例,專案結構如下:
gradle-project
├── app
│ ├── build.gradle // 這裡目前是空的
│ └── ... // Java 程式碼
├── settings.gradle // 包含子專案 'app'
├── gradlew
└── gradlew.bat
我們可以透過執行以下指令來列出 app 子專案的所有可用任務:
$ ./gradlew :app:tasks
這會顯示該子專案中當前可運行的任務。例如我們以上章節提到的hello-quarkus範例執行結果如下
…
pal2097@LAPTOP-IFQHQUQJ:/mnt/d/Project/iThome-Quarkus/hello-quarkus$ ./gradlew tasks --all
> Task :tasks
------------------------------------------------------------
Tasks runnable from root project 'hello-quarkus'
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
integrationTestClasses - Assembles integration test classes.
jar - Assembles a jar archive containing the classes of the 'main' feature.
nativeTestClasses - Assembles native test classes.
quarkusGeneratedSourcesClasses - Assembles quarkus generated sources classes.
quarkusTestGeneratedSourcesClasses - Assembles quarkus test generated sources classes.
testClasses - Assembles test classes.
若要執行某個任務,例如build,可以下指令,就能做建置專案任務
./gradlew build
當 Gradle 執行任務時,會根據不同情況標註任務的執行狀態:
如上述提到的build task執行完後,顯示結果如下,up-to-date表程式未異動,所以不需要重新執行
pal2097@LAPTOP-IFQHQUQJ:/mnt/d/Project/iThome-Quarkus/hello-quarkus$ ./gradlew build
BUILD SUCCESSFUL in 3s
11 actionable tasks: 11 up-to-date
依賴管理 是 Gradle 用來管理專案所需要的外部資源或函式庫的機制。這些外部資源可以是 Java 程式庫、第三方工具包,甚至是其他專案。當專案需要使用某些特定功能時,Gradle 會自動下載並安裝所需的依賴。
依賴管理 是軟體開發中極其重要的一部分,尤其是當專案規模變大時。開發者經常需要使用外部函式庫或工具,而手動管理這些資源不僅繁瑣,而且容易出錯。
Gradle 的依賴管理系統允許開發者聲明專案需要哪些資源,例如某個版本的 JUnit 測試庫或 Spring Framework,然後 Gradle 會自動解決這些依賴並將它們下載到專案中。
例如在 build.gradle
中,可以使用以下程式碼來添加依賴
implementation
表示應用程式在運行時需要 Spring Boot 的 Web Starter,testImplementation
表示單元測試需要使用 JUnit。dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'junit:junit:4.13.2'
}
當 Gradle 在構建專案時,它會按照你定義的依賴關係,下載所需的資源,然後執行每一個任務。整個過程可以想像為一個流水線作業,從開始到結束每個步驟都需要依賴前面的步驟來完成。使用如下簡化的流程圖
|--------------------|
| 任務1:clean | (清理專案的舊檔案)
|--------------------| |
↓ (任務2 依賴於 任務1 完成)
|--------------------|
| 任務2:compile | (編譯 Java 程式碼)
|--------------------| |
↓ (任務3 依賴於 任務2 完成)
|--------------------|
| 任務3:test | (執行單元測試)
|--------------------| |
↓
|--------------------|
| 任務4:build | (打包應用程式)
|--------------------|
大多數專案的工作流程:
上述是較簡單的方式,以下用一個Sample去解釋任務依賴,假設我們有三個任務:task1
、task2
和 task3
,我們將 task3
設置為依賴於 task2
,而 task2
又依賴於 task1
。這樣,當執行 task3
時,Gradle 會確保 task1
和 task2
依次執行。
task3
的依賴:當你運行 gradle task3
時,Gradle 會自動識別出 task3
依賴於 task2
,而 task2
又依賴於 task1
。因此,執行 task3
之前,task1
和 task2
也會被執行。ependsOn
的作用:dependsOn
會確保依賴的任務按順序執行。例如,task3
必須在 task2
完成後執行,而 task2
必須在 task1
完成後執行。這種依賴關係確保了任務之間的協同工作。tasks.register("task1") {
doLast {
println("TASK1: Executing task1")
}
}
tasks.register("task2") {
dependsOn("task1") // task2 依賴於 task1
doLast {
println("TASK2: Executing task2")
}
}
tasks.register("task3") {
dependsOn("task2") // task3 依賴於 task2
doLast {
println("TASK3: Executing task3")
}
}
當你執行 gradle task3
,輸出如下:
TASK1: Executing task1
TASK2: Executing task2
TASK3: Executing task3
如果想進一步體會任務的前後執行流程,可以在每個任務中加入 doFirst
和 doLast
。這樣可以更清楚地看到任務在執行過程中的不同階段。
tasks.register("task1") {
doFirst {
println("TASK1: Preparing to execute task1")
}
doLast {
println("TASK1: Finished executing task1")
}
}
tasks.register("task2") {
dependsOn("task1")
doFirst {
println("TASK2: Preparing to execute task2")
}
doLast {
println("TASK2: Finished executing task2")
}
}
tasks.register("task3") {
dependsOn("task2")
doFirst {
println("TASK3: Preparing to execute task3")
}
doLast {
println("TASK3: Finished executing task3")
}
}
當你運行 gradle task3
時,輸出的順序將會顯示任務在不同階段的執行狀況:
TASK1: Preparing to execute task1
TASK1: Finished executing task1
TASK2: Preparing to execute task2
TASK2: Finished executing task2
TASK3: Preparing to execute task3
TASK3: Finished executing task3
不過大多狀況下,Gradle 的Plugin(如 java
套件或 io.quarkus
套件)已經幫你封裝了構建流程中的一些預設行為。這些預設行為包含了任務的前置和後置處理,並且這些操作可能已經內建到Plugin提供的任務中。
例如,java
套件和 io.quarkus
plugin已經定義好了像 compileJava
、compileTestJava
和 test
等任務,這些任務在內部包含了構建過程中的各種操作,例如編譯、測試和生成構件。在這些預定義的任務中,Gradle 使用了類似 doLast
的方式來封裝每個步驟,但這些步驟對用戶是隱藏的。
Gradle是一個蠻強大的工具,如果要看全貌操作的話,可以到 Gradle的官網(請點我),有一系列的操作解說與練習。