您可以指定具有精確版本或版本範圍的相依性,以定義您的專案可以使用的版本

dependencies {
    implementation("org.springframework:spring-core:5.3.8")
    implementation("org.springframework:spring-core:5.3.+")
    implementation("org.springframework:spring-core:latest.release")
    implementation("org.springframework:spring-core:[5.2.0, 5.3.8]")
    implementation("org.springframework:spring-core:[5.2.0,)")
}

了解版本宣告

Gradle 支援多種宣告版本與範圍的方式

版本 範例 注意

精確版本

1.3, 1.3.0-beta3, 1.0-20150201.131010-1

特定版本。

Maven 樣式範圍

[1.0,), [1.1, 2.0), (1.2, 1.5]

[ ] 表示包含邊界;( ) 表示排除邊界。請參閱 下方內容以了解更多資訊

當缺少上限或下限時,範圍沒有上限或下限。

上限排除作用如同前綴排除。

前綴版本範圍

1.+, 1.3.+

僅包含完全符合 + 之前部分的版本。

宣告版本為 +,不帶任何前綴,將包含任何版本。

latest-status 版本

latest.integration, latest.release

符合具有指定狀態的最高版本。請參閱 ComponentMetadata.getStatus()

Maven SNAPSHOT 版本

1.0-SNAPSHOT, 1.4.9-beta1-SNAPSHOT

表示快照版本。

Maven 樣式範圍

在 Maven 樣式中,有多種選項可以指示邊界

  • [] 表示包含邊界 → [1.1, 2.0]

  • () 表示排除邊界 → (1.1, 2.0)(1.2, 1.5][1.1, 2.0)

  • ] 可以用來代替 ( 表示排除下限 → ]1.2, 1.5] 而非 (1.2, 1.5]

  • [ 可以用來代替 ) 表示排除上限 → [1.1, 2.0[ 而非 [1.1, 2.0)

了解版本排序

dependencies {
    implementation("org.springframework:spring-core:1.1") // This is a newer version than 1.a
    implementation("org.springframework:spring-core:1.a") // This is a older version than 1.1
}

版本排序用於

  • 判斷特定版本是否包含在範圍內。

  • 判斷執行衝突解決時哪個版本最新(使用 「基礎版本」)。

版本根據以下規則排序

  • 將版本拆分為部分

    • 版本使用字元 [. - _ +] 分割為部分。

    • 包含數字和字母的部分會進一步分割,例如,1a1 變成 1.a.1

    • 僅比較部分,不比較分隔符號,因此 1.a.11-a+11.a-11a1 是等效的。(注意:在衝突解決期間有 例外情況)。

  • 比較等效部分

    • 數值與數值:較高的數值被認為較高:1.1 < 1.2

    • 數值與非數值:數值部分高於非數值部分:1.a < 1.1

    • 非數值與非數值:部分按字母順序和區分大小寫比較:1.A < 1.B < 1.a < 1.b

    • 額外數值部分:具有額外數值部分的版本較高,即使它是零:1.1 < 1.1.0

    • 額外非數值部分:具有額外非數值部分的版本較低:1.1.a < 1.1

  • 特殊非數值部分

    • dev 低於任何其他非數值部分:1.0-dev < 1.0-ALPHA < 1.0-alpha < 1.0-rc

    • rcsnapshotfinalgareleasesp 高於任何其他字串部分,依此順序:1.0-zeta < 1.0-rc < 1.0-snapshot < 1.0-final < 1.0-ga < 1.0-release < 1.0-sp

    • 這些特殊值不區分大小寫,且其排序不取決於使用的分隔符號:1.0-RC-1 == 1.0.rc.1

宣告豐富版本

當您使用簡寫符號宣告版本時,該版本會被視為 必要版本

build.gradle.kts
dependencies {
    implementation("org.slf4j:slf4j-api:1.7.15")
}
build.gradle
dependencies {
    implementation('org.slf4j:slf4j-api:1.7.15')
}

這表示最低版本將為 1.7.15,並且可以由引擎樂觀地升級。

為了強制執行 嚴格版本 並確保僅使用相依性的指定版本,即使其他版本通常相容,也拒絕任何其他版本

build.gradle.kts
dependencies {
    implementation("org.slf4j:slf4j-api") {
        version {
            strictly("[1.7, 1.8[")
            prefer("1.7.25")
        }
    }
}
build.gradle
dependencies {
    implementation('org.slf4j:slf4j-api') {
        version {
            strictly '[1.7, 1.8['
            prefer '1.7.25'
        }
    }
}

Gradle 支援豐富版本宣告模型,讓您可以結合不同層級的版本精確度。

關鍵術語,從最強到最弱依序為

strictly!!

這是最強的版本宣告。任何不符合此符號的版本都將被排除。如果用於宣告的相依性,strictly 可以降級版本。對於傳遞相依性,如果找不到可接受的版本,相依性解析將會失敗。

支援動態版本。

定義後,它會覆蓋任何先前的 require 宣告,並清除已在該相依性上宣告的任何先前 reject

require

這確保選定的版本不能低於 require 接受的版本,但可以通過衝突解決更高,即使較高版本具有排除上限。這是直接相依性的預設行為。

支援動態版本。

定義後,它會覆蓋任何先前的 strictly 宣告,並清除已在該相依性上宣告的任何先前 reject

prefer

這是最弱的版本宣告。僅在未指定更強的非動態版本時適用。

此術語不支援動態版本,並且可以補充 strictlyrequire

定義後,它會覆蓋任何先前的 prefer 宣告,並清除已在該相依性上宣告的任何先前 reject

此外,還有一個層次結構之外的術語

reject

此術語指定模組不接受的版本,如果選定拒絕的版本,將導致相依性解析失敗。

支援動態版本。

豐富版本宣告通過相依性或約束宣告上的 version DSL 方法存取,這讓您可以存取 MutableVersionConstraint

build.gradle.kts
dependencies {
    implementation("org.slf4j:slf4j-api") {
        version {
            strictly("[1.7, 1.8[")
            prefer("1.7.25")
        }
    }

    constraints {
        add("implementation", "org.springframework:spring-core") {
            version {
                require("4.2.9.RELEASE")
                reject("4.3.16.RELEASE")
            }
        }
    }
}
build.gradle
dependencies {
    implementation('org.slf4j:slf4j-api') {
        version {
            strictly '[1.7, 1.8['
            prefer '1.7.25'
        }
    }

    constraints {
        implementation('org.springframework:spring-core') {
            version {
                require '4.2.9.RELEASE'
                reject '4.3.16.RELEASE'
            }
        }
    }
}

為了強制執行 嚴格版本,您也可以使用 !! 符號

build.gradle.kts
dependencies {
    // short-hand notation with !!
    implementation("org.slf4j:slf4j-api:1.7.15!!")
    // is equivalent to
    implementation("org.slf4j:slf4j-api") {
        version {
           strictly("1.7.15")
        }
    }

    // or...
    implementation("org.slf4j:slf4j-api:[1.7, 1.8[!!1.7.25")
    // is equivalent to
    implementation("org.slf4j:slf4j-api") {
        version {
           strictly("[1.7, 1.8[")
           prefer("1.7.25")
        }
    }
}
build.gradle
dependencies {
    // short-hand notation with !!
    implementation('org.slf4j:slf4j-api:1.7.15!!')
    // is equivalent to
    implementation("org.slf4j:slf4j-api") {
        version {
           strictly '1.7.15'
        }
    }

    // or...
    implementation('org.slf4j:slf4j-api:[1.7, 1.8[!!1.7.25')
    // is equivalent to
    implementation('org.slf4j:slf4j-api') {
        version {
           strictly '[1.7, 1.8['
           prefer '1.7.25'
        }
    }
}

上面的符號 [1.7, 1.8[!!1.7.25 等同於

  • strictly [1.7, 1.8[

  • prefer 1.7.25

這表示引擎必須選擇介於 1.7(包含)和 1.8(排除)之間的版本。如果圖形中沒有其他組件需要不同的版本,則應偏好 1.7.25

嚴格版本無法升級,並覆蓋任何傳遞相依性版本,因此建議將範圍與嚴格版本一起使用。

下表說明了幾個用例

此相依性的哪些版本是可接受的? strictly require prefer rejects 選擇結果

已使用版本 1.5 測試;相信所有未來版本都應該可以運作。

1.5

任何從 1.5 開始的版本,等同於 org:foo:1.5。接受升級到 2.4

已使用 1.5 測試,根據語意化版本控制進行軟約束升級。

[1.0, 2.0[

1.5

介於 1.02.0 之間的任何版本,如果沒有其他人關心,則為 1.5。接受升級到 2.4
🔒

已使用 1.5 測試,但遵循語意化版本控制。

[1.0, 2.0[

1.5

介於 1.02.0(排除)之間的任何版本,如果沒有其他人關心,則為 1.5
覆蓋來自傳遞相依性的版本。
🔒

與上述相同,但已知 1.4 已損壞。

[1.0, 2.0[

1.5

1.4

介於 1.02.0(排除)之間的任何版本,除了 1.4,如果沒有其他人關心,則為 1.5
覆蓋來自傳遞相依性的版本。
🔒

沒有意見,適用於 1.5

1.5

如果沒有其他意見,則為 1.5,否則為任何版本。

沒有意見,偏好最新發行版本。

latest.release

建置時的最新發行版本。
🔒

在邊緣,最新發行版本,不降級。

latest.release

建置時的最新發行版本。
🔒

除了 1.5 之外沒有其他版本。

1.5

1.5,或如果另一個 strict 或更高的 require 約束不同意,則失敗。
覆蓋來自傳遞相依性的版本。

1.5 或其專用的修補程式版本。

[1.5,1.6[

最新的 1.5.x 修補程式發行版本,或如果另一個 strict 或更高的 require 約束不同意,則失敗。
覆蓋來自傳遞相依性的版本。
🔒

標有鎖 (🔒) 的行表示建議利用 相依性鎖定 的情況。注意:當使用相依性鎖定時,始終建議發布 已解析版本

在函式庫中使用 strictly 需要仔細考慮,因為它會影響下游使用者。但是,當正確使用時,它可以幫助使用者了解哪些函式庫組合在其上下文中可能不相容。有關更多詳細資訊,請參閱關於 覆蓋相依性版本 的章節。

豐富版本資訊保留在 Gradle 模組元資料格式中。但是,將此資訊轉換為 Ivy 或 Maven 元資料格式會造成資訊遺失。最高層級的版本宣告—strictlyrequire 高於 prefer—將會發布,並且任何 reject 都將被忽略。

支持嚴格版本

Gradle 通過選擇在相依性圖形中找到的最大版本來解決任何相依性版本衝突。某些專案可能需要偏離預設行為,並強制執行較早版本的相依性,例如,如果專案的原始碼依賴於比某些外部函式庫更舊的相依性 API。

一般來說,強制相依性是為了降級相依性。降級有一些常見的用例

  • 在最新發行版本中發現了一個錯誤。

  • 您的程式碼依賴於與較新版本不二進位相容的舊版本。

  • 您的程式碼不使用需要較新版本的函式庫部分。

強制執行相依性的版本需要仔細考慮,因為如果外部函式庫期望不同的版本,則更改傳遞相依性的版本可能會導致運行時錯誤。如果可能,通常最好升級您的原始碼以與較新版本相容。

假設一個專案使用 HttpClient 函式庫 執行 HTTP 呼叫。HttpClient 引入 Commons Codec 作為傳遞相依性,版本為 1.10。但是,專案的生產原始碼需要 Commons Codec 1.9 的 API,該 API 在 1.10 中不再可用。可以通過在建置腳本中將相依性版本宣告為 strict 來強制執行

build.gradle.kts
dependencies {
    implementation("org.apache.httpcomponents:httpclient:4.5.4")
    implementation("commons-codec:commons-codec") {
        version {
            strictly("1.9")
        }
    }
}
build.gradle
dependencies {
    implementation 'org.apache.httpcomponents:httpclient:4.5.4'
    implementation('commons-codec:commons-codec') {
        version {
            strictly '1.9'
        }
    }
}

使用嚴格版本的後果

必須仔細考慮使用嚴格版本

  • 對於函式庫作者:嚴格版本實際上就像強制版本。它們優先於傳遞相依性,並覆蓋任何以傳遞方式找到的其他嚴格版本。如果消費者專案需要不同的版本,這可能會導致建置失敗。

  • 對於消費者:在解析期間,嚴格版本被視為全域性的。如果嚴格版本與消費者的版本要求衝突,則會觸發解析錯誤。

例如,如果專案 B strictly 依賴於 C:1.0,但消費者專案 A 需要 C:1.1,則會發生解析錯誤。

為了避免這種情況,建議使用版本範圍以及這些範圍內的偏好版本。

例如,B 可能會說,而不是 strictly 1.0,它嚴格依賴 [1.0, 2.0[ 範圍,但偏好 1.0。然後,如果消費者選擇 1.1(或範圍內的任何其他版本),建置將不再失敗

不宣告版本

對於較大的專案,建議不宣告版本來宣告相依性,並使用 平台 管理版本

build.gradle.kts
dependencies {
    implementation("org.springframework:spring-web")
}

dependencies {
    constraints {
        implementation("org.springframework:spring-web:5.0.2.RELEASE")
    }
}
build.gradle
dependencies {
    implementation 'org.springframework:spring-web'
}

dependencies {
    constraints {
        implementation 'org.springframework:spring-web:5.0.2.RELEASE'
    }
}

這種方法集中管理版本,包括傳遞相依性。

宣告動態版本

在許多情況下,您可能需要使用特定模組相依性的最新版本,或版本範圍內的最新版本。這在開發期間或在建立需要與各種相依性版本相容的函式庫時通常是必要的。專案可能會採用更積極的方法來使用相依性,方法是始終整合最新版本以存取尖端功能。

您可以通過使用動態版本輕鬆管理這些不斷變化的相依性。動態版本可以是版本範圍(例如,2.+)或最新可用版本的佔位符(例如,latest.integration

build.gradle.kts
plugins {
    `java-library`
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework:spring-web:5.+")
}
build.gradle
plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework:spring-web:5.+'
}

使用動態版本和變更模組可能會導致無法重現的建置。隨著模組的新版本發布,其 API 可能會與您的原始碼不相容。因此,請謹慎使用此功能。

為了實現可重現的建置,在宣告具有動態版本的相依性時,務必使用 相依性鎖定。如果沒有這個,即使對於相同的版本,您請求的模組也可能會更改,這被稱為 變更版本。例如,Maven SNAPSHOT 模組始終指向發布的最新 artifact,使其成為「變更模組」。

宣告變更版本

團隊可能會在發布應用程式或函式庫的新版本之前實作一系列功能。一種常見的策略是允許消費者盡早整合其 artifact 的未完成版本,即發布具有變更版本的模組。變更版本表示功能集仍在積極開發中,並且尚未發布用於一般可用性的穩定版本。

在 Maven 儲存庫中,變更版本通常稱為 快照版本。快照版本包含後綴 -SNAPSHOT

以下範例示範如何在 Spring 相依性上宣告快照版本

build.gradle.kts
plugins {
    `java-library`
}

repositories {
    mavenCentral()
    maven {
        url = uri("https://repo.spring.io/snapshot/")
    }
}

dependencies {
    implementation("org.springframework:spring-web:5.0.3.BUILD-SNAPSHOT")
}
build.gradle
plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
    maven {
        url = 'https://repo.spring.io/snapshot/'
    }
}

dependencies {
    implementation 'org.springframework:spring-web:5.0.3.BUILD-SNAPSHOT'
}

Gradle 非常靈活,可以將任何版本視為變更版本。您只需將屬性 ExternalModuleDependency.setChanging(boolean) 設置為 true 即可。