在許多情況下,您會想要使用特定模組相依性的最新版本,或版本範圍內的最新版本。這可能是開發期間的要求,或者您可能正在開發一個旨在與各種相依性版本搭配使用的函式庫。您可以透過使用動態版本輕鬆依賴這些持續變更的相依性。動態版本可以是版本範圍(例如 2.+
),也可以是可用最新版本的佔位符,例如 latest.integration
。
或者,您要求的模組可能會隨著時間而改變,即使是相同版本,也稱為變更版本。此類變更模組的範例是 Maven SNAPSHOT
模組,它總是指向發布的最新成品。換句話說,標準 Maven 快照是一個持續演進的模組,它是一個「變更模組」。
使用動態版本和變更模組可能會導致無法重製的組建。由於特定模組的新版本已發布,其 API 可能與您的原始碼不相容。請謹慎使用此功能! |
宣告動態版本
專案可能會採用更積極的方式來使用模組的相依性。例如,您可能想要隨時整合相依性的最新版本,以隨時使用尖端功能。動態版本允許解析特定模組的最新版本或版本範圍的最新版本。
在建置中使用動態版本可能會造成中斷的風險。一旦相依性的新版本釋出,其中包含不相容的 API 變更,您的原始碼可能會停止編譯。 |
plugins {
`java-library`
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework:spring-web:5.+")
}
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework:spring-web:5.+'
}
建置掃描可以有效視覺化動態相依性版本及其各自選取的版本。

預設情況下,Gradle 會快取相依性的動態版本 24 小時。在此時間範圍內,Gradle 不會嘗試從宣告的儲存庫解析較新的版本。可以視需要設定臨界值,例如,如果您想要提早解析新版本。
宣告變更版本
團隊可能會決定在釋出應用程式或函式庫的新版本之前,先實作一系列功能。允許使用者提早且頻繁整合未完成版本的成品的常見策略,是釋出具有所謂變更版本的模組。變更版本表示功能集仍處於積極開發中,尚未釋出一般可用的穩定版本。
在 Maven 儲存庫中,變更版本通常稱為快照版本。快照版本包含字尾 -SNAPSHOT
。下列範例示範如何宣告 Spring 相依性的快照版本。
plugins {
`java-library`
}
repositories {
mavenCentral()
maven {
url = uri("https://repo.spring.io/snapshot/")
}
}
dependencies {
implementation("org.springframework:spring-web:5.0.3.BUILD-SNAPSHOT")
}
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 會快取變更版本的相依項 24 小時。在此時間範圍內,Gradle 不會嘗試從宣告的儲存庫解析較新的版本。閾值可以依需要進行設定,例如如果您想提早解析新的快照版本。
Gradle 夠靈活,可以將任何版本視為變更版本,例如如果您想為 Ivy 模組建模快照行為。您只需將屬性 ExternalModuleDependency.setChanging(boolean) 設定為 true
即可。
以程式方式控制相依項快取
您可以使用設定檔的 ResolutionStrategy 以程式方式微調快取的特定面向。如果您想要永久變更設定,以程式方式進行會很有用。
預設情況下,Gradle 會快取動態版本 24 小時。若要變更 Gradle 快取動態版本解析版本的時間長度,請使用
configurations.all {
resolutionStrategy.cacheDynamicVersionsFor(10, "minutes")
}
configurations.all {
resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}
預設情況下,Gradle 會快取變更模組 24 小時。若要變更 Gradle 快取變更模組的元資料和人工製品的時間長度,請使用
configurations.all {
resolutionStrategy.cacheChangingModulesFor(4, "hours")
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 4, 'hours'
}
從命令列控制相依項快取
避免網路存取與離線模式
--offline
命令列開關會指示 Gradle 永遠使用快取中的相依模組,而不管是否需要再次檢查。在離線執行時,Gradle 永遠不會嘗試存取網路來執行相依解析。如果相依快取中沒有必要的模組,建置執行會失敗。
重新整理相依
您可以從命令列控制相依快取在特定建置呼叫中的行為。命令列選項有助於在單一建置執行中做出選擇性的臨時選擇。
有時,Gradle 相依快取會與設定儲存庫的實際狀態不同步。可能是儲存庫最初設定錯誤,或可能是「不變更」模組發布錯誤。若要重新整理相依快取中的所有相依,請在命令列上使用 --refresh-dependencies
選項。
--refresh-dependencies
選項會指示 Gradle 忽略已解析模組和人工製品的所有快取項目。系統會針對所有設定的儲存庫執行新的解析,重新計算動態版本、重新整理模組和下載人工製品。不過,在可能的情況下,Gradle 會在再次下載之前檢查先前下載的人工製品是否有效。這會透過將儲存庫中發布的 SHA1 值與現有已下載人工製品的 SHA1 值進行比較來完成。
-
動態相依的新版本
-
變更模組的新版本(使用相同版本字串但內容可能不同的模組)
重新整理相依會導致 Gradle 宣告其清單快取無效。不過
-
它會對元資料檔執行 HTTP HEAD 要求,但如果它們相同,不會重新下載它們
-
它會對人工製品檔執行 HTTP HEAD 要求,但如果它們相同,不會重新下載它們
換句話說,重新整理相依只有在您實際使用動態相依或您有未察覺的變更相依(在這種情況下,您有責任正確地向 Gradle 宣告它們為變更相依)時才會產生影響。
認為使用 --refresh-dependencies
會強制下載相依是一個常見的誤解。並非如此:Gradle 只會執行重新整理動態相依所絕對需要的動作。這可能涉及下載新的清單或元資料檔,甚至人工製品,但如果沒有變更,影響就會很小。
使用元件選取規則
元件選取規則可能會影響在多個符合版本選擇器的版本可用時,應該選取哪個元件實例。規則會套用至每個可用的版本,並允許版本透過規則明確地被拒絕。這允許 Gradle 忽略任何不符合規則設定條件的元件實例。範例包括
-
對於動態版本(例如
1.+
),某些版本可能會明確地從選取中拒絕。 -
對於靜態版本(例如
1.4
),可能會根據額外的元件元資料(例如 Ivy 分支屬性)拒絕實例,允許使用來自後續儲存庫的實例。
規則透過 ComponentSelectionRules 物件進行設定。設定的每個規則會以 ComponentSelection 物件作為引數呼叫,其中包含有關所考慮的候選版本的資訊。呼叫 ComponentSelection.reject(java.lang.String) 會導致明確地拒絕指定的候選版本,在這種情況下,候選版本將不會被選擇器考慮。
以下範例顯示一個規則,禁止使用模組的特定版本,但允許動態版本選取下一個最佳候選版本。
configurations {
create("rejectConfig") {
resolutionStrategy {
componentSelection {
// Accept the highest version matching the requested version that isn't '1.5'
all {
if (candidate.group == "org.sample" && candidate.module == "api" && candidate.version == "1.5") {
reject("version 1.5 is broken for 'org.sample:api'")
}
}
}
}
}
}
dependencies {
"rejectConfig"("org.sample:api:1.+")
}
configurations {
rejectConfig {
resolutionStrategy {
componentSelection {
// Accept the highest version matching the requested version that isn't '1.5'
all { ComponentSelection selection ->
if (selection.candidate.group == 'org.sample' && selection.candidate.module == 'api' && selection.candidate.version == '1.5') {
selection.reject("version 1.5 is broken for 'org.sample:api'")
}
}
}
}
}
}
dependencies {
rejectConfig "org.sample:api:1.+"
}
請注意,版本選取會從最高版本開始套用。選取的版本將會是所有元件選取規則都接受的第一個版本。如果沒有規則明確地拒絕版本,則該版本會被視為已接受。
類似地,規則可以針對特定模組。模組必須以 group:module
的形式指定。
configurations {
create("targetConfig") {
resolutionStrategy {
componentSelection {
withModule("org.sample:api") {
if (candidate.version == "1.5") {
reject("version 1.5 is broken for 'org.sample:api'")
}
}
}
}
}
}
configurations {
targetConfig {
resolutionStrategy {
componentSelection {
withModule("org.sample:api") { ComponentSelection selection ->
if (selection.candidate.version == "1.5") {
selection.reject("version 1.5 is broken for 'org.sample:api'")
}
}
}
}
}
}
元件選取規則在選取版本時也可以考慮元件元資料。可以考慮的額外元資料可能是 ComponentMetadata 和 IvyModuleDescriptor。請注意,這些額外資訊可能並不總是可用,因此應該檢查 null
值。
configurations {
create("metadataRulesConfig") {
resolutionStrategy {
componentSelection {
// Reject any versions with a status of 'experimental'
all {
if (candidate.group == "org.sample" && metadata?.status == "experimental") {
reject("don't use experimental candidates from 'org.sample'")
}
}
// Accept the highest version with either a "release" branch or a status of 'milestone'
withModule("org.sample:api") {
if (getDescriptor(IvyModuleDescriptor::class)?.branch != "release" && metadata?.status != "milestone") {
reject("'org.sample:api' must have testing branch or milestone status")
}
}
}
}
}
}
configurations {
metadataRulesConfig {
resolutionStrategy {
componentSelection {
// Reject any versions with a status of 'experimental'
all { ComponentSelection selection ->
if (selection.candidate.group == 'org.sample' && selection.metadata?.status == 'experimental') {
selection.reject("don't use experimental candidates from 'org.sample'")
}
}
// Accept the highest version with either a "release" branch or a status of 'milestone'
withModule('org.sample:api') { ComponentSelection selection ->
if (selection.getDescriptor(IvyModuleDescriptor)?.branch != "release" && selection.metadata?.status != 'milestone') {
selection.reject("'org.sample:api' must be a release branch or have milestone status")
}
}
}
}
}
}
請注意,在宣告元件選取規則時,ComponentSelection 引數總是需要作為參數。