Maven 程序員難道就不能快速上手 Gradle了嗎?

背景

庖丁同學在混跡在古典互聯網界多年,構建 Java 應用程序一直都是使用Apache Maven,mvn的那幾個常用命令早已爛熟於心,在加上現代 IDE 越來越智能,應用程序的構建從來就不是事兒,但是驚喜總會出現,有一天,庖丁的工作性質發生了改變,眼前的構建工具清一色的都是 Gradle,庖丁一臉的懵逼,束手無策,難道Maven 程序員就不能快速上手 Gradle了嗎?

實戰性或者戰術性程序員這時候做的第一件是事情,肯定是先打開 Gradle 的官方網站,快速學習一遍入門教程,先用起來,再去慢慢理解它的運行機制和設計思想,但是庖丁是解牛的,必須“依乎天理”。深刻理解事物的本質,方能遊刃有餘。

首先回歸問題的本質,無論是 Apache Maven 還是 Gradle ,最核心的功能都是應用程序工程的構建工具,只是實現理念和使用方式上有差異。下面庖丁首先回顧下 Apache Maven 的使用方式和工作機制。

Apache Maven 的工作機制

Maven 程序員難道就不能快速上手 Gradle了嗎?

Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.

上面這段話來自於 Apache Maven 的官網,Apache Maven是一個軟件項目管理和理解工具。 基於項目對象模型(POM)的概念,Maven可以通過集中的信息來管理項目的構建,報告和文檔。POM 是最基礎也是最核心的組件,這也是 Maven 的配置文件命名為 pom.xml的主要原因。POM是通過 XML 文件的格式進行定義。pom.xml 文檔的示例片段如下:

<code> <project>   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                       http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelversion>4.0.0/<modelversion>
   <groupid>com.mycompany.app/<groupid>
   <artifactid>my-app/<artifactid>
   <packaging>jar/<packaging>
   <version>1.0-SNAPSHOT/<version>
   <name>Maven Quick Start Archetype/<name>
   http://maven.apache.org
   <dependencies>
     <dependency>
       <groupid>junit/<groupid>
       <artifactid>junit/<artifactid>
       <version>4.11/<version>
       <scope>test/<scope>
     /<dependency>
   /<dependencies>
 /<project>/<code>

使用 Maven 管理項目構建時,通常第一步去官網下載Apache Maven 的安裝包,配置好環境變量,就可以執行 mvn 命令了,大多數公司會通過 nexus搭建私服,對項目的依賴進行規劃化管理。

我們在使用 Maven 管理項目的構建時,IDE 工具或者腳手架工具都會幫我們生成 pom.xml 文件和基本的項目骨架,然後根據項目的需要進行依賴管理,各種各樣的插件是必不可少的。一切準備就緒後,我們就可以對項目進行構建了,例如編譯,測試,部署等工作。所以Apache Maven 主要幫我們做了兩件大事,一個是依賴版本管理,另一個就是各種構建過程。先看看Apache Maven 的構建過程。

Maven的構建過程

下面是Maven讀取POM文件執行構建過程的示意圖

Maven 程序員難道就不能快速上手 Gradle了嗎?

Maven 構建過程

Maven 的構建過程

總體來說,Maven項目的構建分為五個主要步驟,

  1. 讀取 POM.xml 文件
  2. 選擇需要構建的 profile,這個主要方便多構建目標操作,例如單元測試和集成測試,依賴項不一樣
  3. 下載依賴項目,一般是 Jar 包文件,首先回去讀本地倉庫,然後選擇讀取內部私服,最後是遠程公共倉庫
  4. 根據構建任務的生命週期,執行構建過程和目標
  5. 執行插件,部分插件會融合在構建階段中,一起執行。

例如對於編譯這個構建任務,執行如下命令:

<code> mvn compile/<code>

實際上,執行是編譯 compile 這個構建階段,真正執行的是如下階段

  1. validate
  2. generate-sources
  3. process-sources
  4. generate-resources
  5. process-resources
  6. compile

maven 對構建過程的抽象

項目的研發有生命週期,項目的構建過程也一樣,是多個獨立的任務,Maven 對構建構建過程的抽象中,任務是個虛擬的概念, 因為Maven基於構建生命週期的中心概念。這意味著已明確定義了構建和分發特定工件(項目)的過程。對於構建項目的人來說,這意味著僅需學習少量命令即可構建任何Maven項目,並且POM將確保它們獲得所需的結果。這是一種開箱即用的設計,也是一種最佳實踐。

POM 文件

執行Maven命令時,Maven根據POM文件中的配置來執行命令。

依賴項和存儲庫

Pom文件包含了依賴項的配置,依賴項是項目使用的外部JAR文件(Java庫)。如果本地庫中沒有找到依賴項,Maven將從中央庫下載依賴項,並存放在本地庫中。本地存儲庫只是本機上的一個目錄,這個目錄位置可配置。另外除了中央庫,還可以配置其他遠程庫,例如公司內部可以架設一個遠程庫供所有開發人員使用。這裡我們看看 Spring Boot 的依賴項,通過三個維度對依賴包進行管理。

<code> 
 <dependency>
     <groupid>org.springframework.boot/<groupid>
     <artifactid>spring-boot-starter-web/<artifactid>
     <version>2.2.6.RELEASE/<version>
 /<dependency>/<code>

構建生命週期、階段和目標

項目的構建通常包含數個相互獨立的任務,可以獨立執行,如生成文檔,構建jar包等。單個任務的執行過程被稱為一個構建生命週期,構建生命週期由一系列的構建階段組成,這些構建生命週期中的每一個都由不同的構建階段列表定義,其中,構建階段代表生命週期中的一個階段。每個階段包含一系列的構建目標。

可以執行構建階段或構建目標。階段按順序執行,執行一個階段則會先執行該階段之前的所有階段。當執行構建階段時,將會按順序執行其中包含的所有構建目標。構建目標可以被分配到一個或多個構建階段。還可以直接執行構建目標。

Maven有三個內置的構建生命週期:默認(default),清除(clean)和站點(site)。默認生命週期處理項目部署,清理(clean)生命週期處理項目清理,而站點(site)生命週期處理項目的站點文檔的創建。

例如,默認生命週期包含以下階段:

  • 驗證(validate)-驗證項目是否正確並且所有必要信息均可用
  • 編譯(compile)-編譯項目的源代碼
  • 測試(test)-使用合適的單元測試框架測試已編譯的源代碼。這些測試不應要求將代碼打包或部署
  • 打包(package)-打包已編譯的代碼,並將其打包為可分發的格式,例如JAR。
  • 集成測試(integration-test):處理程序包並將其部署到可以運行集成測試的環境中
  • 驗證(verify):運行任何檢查以驗證包裝是否有效並符合質量標準
  • 安裝(install):將軟件包安裝到本地存儲庫中,以作為本地其他項目中的依賴項
  • 部署(deploy):在集成或發佈環境中完成,將最終程序包複製到遠程存儲庫,以便與其他開發人員和項目共享。

插件Plugin

插件是構建目標的集合,也稱為MOJO (Maven Old Java Object)。可以把插件理解為一個類,而構建目標是類中的方法。構建階段包含一系列的構建目標,可以理解為按順序調用各個插件中的構建目標(方法),然後一系列的構建階段組成一個構建生命週期。

Maven實際上是一個插件執行框架。如有必要,可以用java開發自定義插件。例如我們經常使用的Running MyBatis Generator With Maven

構建Profile

如果需要構建項目的不同版本,可以使用構建profile。例如,項目中需要構建開發版本、測試版本以及正式版本,這些版本可以通過在pom文件中添加不同構建profile構建。執行maven時指定不同的構建profile就可以。

小結

Apache Maven是一個軟件項目管理和理解工具。 基於項目對象模型(POM)的概念,通過 XML 進行配置,構建過程基於任務的的生命週期概念。完成了依賴版本管理和項目構建過程。

對 Gradle 工具的猜想

既然 Maven 已經使用了挺好了,為什麼會出現新的構建工具之一 Gradle 呢?顯然 Maven 有不足之處或者痛點,想想我們日常工作中的痛點。

  • pom.xml文件非常冗長,例如 Apache Flink 的 pom(https://github.com/apache/flink/blob/master/pom.xml) 文件大概有兩千行,這和 XML 的表達方式有關。
  • 構建過程非常慢,特別是大型項目。
  • 擴展性限制較大,無法和你的編程語言或者腳本打通

如果需要一個新的構建工具,你期望它最好具有哪些特徵呢?

  • 兼容 Maven 的依賴管理機制,畢竟你已經有一些項目通過 Maven 管理,當然還有一些非常優秀的第三方 Jar 包,這些對你的項目運行至關重要
  • 編譯和構建速度快
  • 構建文件的配置簡單明瞭,減少冗餘,特別是那些約定俗稱的概念
  • 擴張性好,最好能和你使用的 Java 語言打通

萬變不離其宗,構建工具的本質工作為依賴管理和項目構建,那麼 Gradle 會不會給你驚喜呢?

Gradle 初見

驚訝地發現,熟悉的 pom.xml 文件不見了,取而代之的是 build.gradle文件,打開它發現 XML 格式的內容也不見了,莫慌,肯定是某種編程語言,先瞄一眼,build.gradle 腳本示例。

<code> plugins {
     id 'java-library'
 }
 ​
 repositories {
  mavenCentral()
     jcenter()
 }
 dependencies {
     api 'org.apache.commons:commons-math3:3.6.1'
     implementation 'com.google.guava:guava:28.0-jre'
     testImplementation 'junit:junit:4.13'
 }/<code>

挺簡潔,junit 的依賴一行就闡述清楚了

<code> testCompile group: 'junit', name: 'junit', version: '4.13'/<code>

如果使用 Maven 的依賴,配置片段應該是如下這樣,6 行配置代碼,解決了配置文件冗長的 繁瑣,並且提高了可讀性。

<code> <dependency>
     <groupid>junit/<groupid>
     <artifactid>junit/<artifactid>
     <version>4.13/<version>
     <scope>test/<scope>
 /<dependency>/<code>

mavenCentral(),具備Jar 包存儲倉庫管理和配置,兼容 Maven 倉庫,簡潔的依賴管理和可配置的插件。已經具備了 Maven的基礎功能。Gradle能不能解決 Maven 構建工具的痛點呢?它和Maven 對於項目構建過程的抽象和封裝會一致嗎?

Gradle 的工作機制

Gradle 簡介

Gradle是一個開放源代碼的構建自動化工具,旨在靈活地構建幾乎任何類型的軟件。下圖是 Gradle 官網的截圖,可以看出 Gradle 的雄心,加快研發人員的生產力


Maven 程序員難道就不能快速上手 Gradle了嗎?


Gradle是專注於靈活性和性能的開源構建自動化工具。 Gradle構建腳本是使用[Groovy](https://groovy-lang.org/)或[Kotlin](https://kotlinlang.org/)DSL編寫的,主要有如下特質:

  • 高度可定製-Gradle以最基本的方式可定製和可擴展的方式建模。
  • 快速-Gradle通過重新使用先前執行的輸出,僅處理已更改的輸入並並行執行任務來快速完成任務。**
  • 功能強大–Gradle是Android的官方構建工具,並支持許多流行的語言和技術。
Maven 程序員難道就不能快速上手 Gradle了嗎?

Gradle 重要核心功能

高性能

Gradle通過僅運行需要執行的任務來避免不必要的工作,因為它們的輸入或輸出已更改。您還可以使用構建緩存來重用以前運行的任務輸出,甚至可以使用其他計算機(具有共享的構建緩存)重用任務輸出。

Gradle還實施了許多其他優化措施,並且開發團隊不斷努力以提高Gradle的性能。

JVM基礎

Gradle在JVM上運行,並且必須安裝Java開發工具包(JDK)才能使用它。對於熟悉Java平臺的用戶來說,這是一個好處,因為您可以在構建邏輯中使用標準Java API,例如自定義任務類型和插件。它還使在不同平臺上運行Gradle變得容易。

請注意,Gradle不僅限於構建JVM項目,它甚至附帶對構建本機項目的支持。

約定(Conventions)

Gradle從Maven的書中抽出了一片葉子,並通過實現約定使常見類型的項目(例如Java項目)易於構建。應用適當的插件,您可以輕鬆地為許多項目使用苗條的構建腳本。但是這些約定並沒有限制您:Gradle允許您覆蓋它們,添加自己的任務以及對基於約定的版本進行許多其他自定義。

可擴展性

您可以輕鬆擴展Gradle以提供您自己的任務類型甚至構建模型。有關此示例,請參見Android構建支持:它添加了許多新的構建概念,例如口味和構建類型。

IDE支持

幾個主要的IDE允許您導入Gradle構建並與其進行交互:Android Studio,IntelliJ IDEA,Eclipse和NetBeans。 Gradle還支持生成將項目加載到Visual Studio所需的解決方案文件。

洞察力

構建掃描提供了有關構建運行的廣泛信息,可用於識別構建問題。他們特別擅長幫助您發現構建性能方面的問題。您還可以與其他人共享構建掃描,如果您需要諮詢以解決構建問題,這特別有用。

主要差異和對比

Gradle和Maven之間的主要區別是靈活性,性能,用戶體驗和依賴性管理。 Maven與Gradle功能比較中提供了這些方面的直觀概述。Gradle 官網中,對 Gradle 和 Maven 從以下幾個方面做了比較詳細的對比:

靈活性

Google選擇Gradle作為Android的官方構建工具; 不是因為構建腳本是代碼,而是因為Gradle以最基本的方式可擴展的方式進行建模。 Gradle的模型還允許將其用於C / C ++的本機開發,並且可以擴展為涵蓋任何生態系統。 例如,Gradle在設計時會考慮使用其Tooling API進行嵌入。

Gradle和Maven都提供了配置約定。 但是,Maven提供了一個非常僵化的模型,使定製變得乏味,有時甚至是不可能的。 儘管這可以使您更容易理解任何給定的Maven構建,但是隻要您沒有任何特殊要求,它也就不適合許多自動化問題。 另一方面,Gradle的構建考慮了授權和負責任的用戶。

性能

縮短構建時間是提高交付速度的最直接方法之一。 Gradle和Maven都採用某種形式的並行項目構建和並行依賴項解析。 最大的差異是Gradle避免重複工作和增加工作量的機制。 使Gradle比Maven快得多的前3個功能是:

  1. 增量性-Gradle通過跟蹤任務的輸入和輸出並僅運行必要的內容,並且僅在可能時處理已更改的文件,從而避免了工作。
  2. Build Cache(構建緩存)—重用具有相同輸入的任何其他Gradle構建的構建輸出,包括在機器之間
  3. Gradle Daemon —一個長期存在的過程,可將構建信息“熱”存儲在內存中。

在Gradle與Maven的性能對比中,這些和更多的性能特性使Gradle在幾乎每種情況下的速度至少是其兩倍(對於使用構建緩存的大型構建而言,則要快100倍)。下圖來自 Gradle 官網 。

Maven 程序員難道就不能快速上手 Gradle了嗎?

用戶體驗

Maven的任期較長,這意味著它對許多用戶來說都更支持IDE。 但是,Gradle的IDE支持繼續迅速提高。 例如,Gradle現在具有基於Kotlin的DSL,可提供更好的IDE體驗。 Gradle團隊正在與IDE開發商合作,以使編輯支持變得更好-隨時關注更新。

Maven 程序員難道就不能快速上手 Gradle了嗎?

儘管IDE很重要,但是許多用戶還是喜歡通過命令行界面執行構建操作。 Gradle提供了一個現代的CLI,該CLI具有可發現性功能,例如“ gradle task”(漸變任務),以及改進的日誌記錄和命令行完成功能。

最後,Gradle提供了一個基於Web的交互式UI,用於調試和優化構建:構建掃描。 這些也可以在內部託管,以允許組織收集構建歷史記錄並進行趨勢分析,比較構建以進行調試或優化構建時間。

Maven 程序員難道就不能快速上手 Gradle了嗎?

依賴管理

兩種構建系統都提供了內置功能,可以解決來自可配置存儲庫的依賴關係。兩者都可以在本地緩存依賴項並並行下載它們。

作為庫的使用者,Maven允許重寫一個依賴項,但只能按版本。 Gradle提供了可自定義的依賴關係選擇和替換規則,這些規則可以聲明一次,並在項目範圍內處理不需要的依賴關係。這種替換機制使Gradle可以一起構建多個源項目以創建複合構建。

Maven具有很少的內置依賴項作用域,這些作用域在常見的情況下(例如使用測試夾具或代碼生成)迫使笨拙的模塊體系結構。例如,單元測試和集成測試之間沒有分隔。 Gradle允許自定義依賴項範圍,從而提供了更好的建模和更快的構建。

Maven依賴關係衝突解決方案使用最短路徑,這受聲明順序影響。 Gradle可以完全解決衝突,選擇圖中最高版本的依賴項。此外,使用Gradle可以將版本嚴格聲明為允許其優先於傳遞版本的版本,從而可以降級依賴項。

作為庫生產者,Gradle允許生產者聲明“ api”和“實現”依賴項,以防止有害的庫洩漏到使用者的類路徑中。 Maven允許發佈者通過可選的依賴項提供元數據,但僅作為文檔提供。 Gradle完全支持功能變體和可選的依賴項。

Maven 程序員難道就不能快速上手 Gradle了嗎?

以上從四個方面對 Gradle 和 Maven 進行了對比,差距確實明顯,但闡述都比較表象,沒有深刻闡述本質的區別。Gradle和Maven對如何構建項目有根本不同的視角。 Gradle提供了一個靈活且可擴展的構建模型,該模型將實際工作委託給任務依賴關係圖。 Maven使用固定,線性階段的模型,您可以在其中附加目標(完成工作的事物)。 這可能使兩者之間的遷移看起來令人生畏,但是遷移可能出奇的容易,因為Gradle遵循許多與Maven相同的約定(例如標準項目結構),並且其依賴項管理以類似的方式工作。

所以任務依賴關係圖和線性階段模型才是本質上的差別,也是研發和使用人員認知上的本質差別。

Maven 到 Gradle,認知的轉變

Gradle是一種靈活而強大的構建工具,當Maven 程序員初次啟動時,很容易感到恐懼。但是,瞭解以下核心原則將使Gradle更加容易上手,並且您將在不知道該工具的情況下熟練掌握該工具。

Gradle是通用的構建工具

Gradle允許您構建任何軟件,因為它對您要構建的內容或應如何完成的工作幾乎沒有任何假設。最明顯的限制是,依賴項管理當前僅支持與Maven和Ivy兼容的存儲庫以及文件系統。

這並不意味著您需要做很多工作來創建構建。 Gradle通過添加一層約定和通過插件的預構建功能,可以輕鬆構建通用類型的項目(例如Java庫)。您甚至可以創建和發佈自定義插件來封裝自己的約定並構建功能。

核心模型基於任務

Gradle將其構建模型建模為任務(工作單元)的有向無環圖(DAG)。這意味著構建實質上配置了一組任務,並根據它們的依賴關係將它們連接在一起以創建該DAG。創建任務圖後,Gradle將確定需要按順序運行的任務,然後繼續執行它們。

此圖顯示了兩個示例任務圖,一個是抽象圖,另一個是具體圖,其中任務之間的依賴性表示為箭頭:

Maven 程序員難道就不能快速上手 Gradle了嗎?

這樣,幾乎所有構建過程都可以建模為任務圖,這就是Gradle如此靈活的原因之一。任務圖可以由插件和您自己的構建腳本定義,任務通過任務依賴機制鏈接在一起。

任務本身包括:

  • 動作-做某事的工作,例如複製文件或編譯源代碼
  • 輸入-操作使用或對其進行操作的值,文件和目錄
  • 輸出-操作修改或生成的文件和目錄

實際上,以上所有操作都是可選的,具體取決於任務需要執行的操作。某些任務(例如標準生命週期任務)甚至沒有任何動作。他們只是為了方便而將多個任務聚合在一起。

您選擇要運行的任務。通過指定執行所需任務的任務來節省時間,但僅此而已。如果您只想運行單元測試,請選擇執行該任務的任務-通常是測試。如果要打包應用程序,則大多數構建都為此執行組裝任務。最後一件事:Gradle的增量構建支持是可靠且可靠的,因此,除非您確實想執行清理,否則避免清理任務可保持構建快速運行。

Gradle有幾個固定的構建階段

重要的是要了解Gradle分三個階段評估和執行構建腳本:

  1. 初始化:設置構建環境,並確定哪些項目將參與其中。
  2. 配置:構造和配置用於構建的任務圖,然後根據用戶要運行的任務確定需要運行的任務和運行順序。
  3. 執行: 運行在配置階段結束時選擇的任務。

這些階段構成了Gradle的構建生命週期。

與Apache Maven術語的比較Gradle的構建階段與Maven的階段不同。 Maven使用其階段將構建執行分為多個階段。它們的作用類似於Gradle的任務圖,但靈活性較差。

Maven的構建生命週期概念與Gradle的生命週期任務大致相似。

設計良好的構建腳本主要由聲明性配置而不是命令式邏輯組成。可以理解,在配置階段評估該配置。即便如此,許多此類構建也具有任務操作(例如,通過doLast {}和doFirst {}塊),這些任務在執行階段進行評估。這很重要,因為在配置階段評估的代碼不會看到在執行階段發生的更改。

配置階段的另一個重要方面是,每次運行構建時都要評估其中涉及的所有內容。因此,最佳做法是在配置階段避免昂貴的工作。構建掃描可以幫助您識別此類熱點。

Gradle的擴展方式不止一種

如果您僅可以使用Gradle捆綁的構建邏輯來構建項目,那將是很好的選擇,但這幾乎是不可能的。大多數構建都有一些特殊要求,這意味著您需要添加自定義構建邏輯。

Gradle提供了多種機制來擴展它,例如:

  • 自定義任務類型。

當您希望構建完成現有任務無法完成的工作時,只需編寫自己的任務類型即可。通常,最好將自定義任務類型的源文件放在buildSrc目錄或打包的插件中。然後,您可以像Gradle提供的任何任務一樣使用自定義任務類型。

  • 自定義任務動作。

您可以通過Task.doFirst()和Task.doLast()方法附加在任務之前或之後執行的自定義構建邏輯。

  • 項目和任務的額外屬性。

這些允許您將自己的屬性添加到項目或任務中,然後可以從您自己的自定義操作或任何其他構建邏輯中使用它們。甚至可以將額外的屬性應用於您未明確創建的任務,例如Gradle的核心插件創建的任務。

  • 自定義約定。

約定是簡化構建的強大方法,因此用戶可以更輕鬆地理解和使用它們。從使用標準項目結構和命名約定的構建(例如Java構建)中可以看出這一點。您可以編寫自己的提供約定的插件-它們只需要為構建的相關方面配置默認值。

  • 自定義模型。

Gradle允許您將新概念引入除任務,文件和依賴項配置之外的內部版本。您可以在大多數語言插件中看到這一點,這些插件將源集的概念添加到了構建中。對構建過程進行適當的建模可以大大提高構建的易用性及其效率。

構建腳本針對API運行

將Gradle的構建腳本視為可執行代碼很容易,因為它們就是這樣。但這只是一個實現細節:精心設計的構建腳本描述了構建軟件所需的步驟,而不是這些步驟應如何工作。這是定製任務類型和插件的工作。

人們普遍誤認為Gradle的功能和靈活性來自其構建腳本是代碼這一事實。這離事實還遠。強大的基礎模型和API。正如我們在最佳實踐中建議的那樣,您應該避免在構建腳本中放置太多(如果有的話)命令式邏輯。

然而,在一個區域中,將構建腳本視為可執行代碼很有用:瞭解構建腳本的語法如何映射到Gradle的API。由Groovy DSL參考和Javadocs組成的API文檔列出了方法和屬性,並引用了閉包和操作。這些在構建腳本的上下文中是什麼意思?查看Groovy Build Script Primer,以瞭解該問題的答案,以便您可以有效地使用API文檔。

由於Gradle在JVM上運行,因此構建腳本也可以使用標準Java API。 Groovy構建腳本可以另外使用Groovy API,而Kotlin構建腳本可以使用Kotlin。

總結

通過對 Maven 和Gradle 工作機制的介紹,Maven 程序員對於如何使用 Gradle 有個認知上的提升,Gradle和Maven對如何構建項目有根本不同的視角。 Gradle提供了一個靈活且可擴展的構建模型,該模型將實際工作委託給

任務依賴關係圖。 Maven使用固定,線性階段的模型,您可以在其中附加目標(完成工作的事物)。從構架項目這個領域模型來看,有個本質的差別,從而引起架構設計的差異,因此 Maven 程序員必須深刻理解這個差異,提升認知,就可以快速上手。而依賴管理,兩個各有千秋,但差異不大。

  • Apache Maven 官網:http://maven.apache.org/
  • https://stackoverflow.com/questions/7249871/what-is-a-build-tool
  • https://gradle.org/


分享到:


相關文章: