你可以使用确切版本或版本范围来指定依赖,以定义你的项目可以使用哪些版本
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 支持多种方式来声明版本和范围
版本 | 示例 | 注意 |
---|---|---|
确切版本 |
|
一个特定的版本。 |
Maven 风格范围 |
|
当上限或下限缺失时,该范围没有上限或下限。 排除上限相当于排除某个前缀。 |
前缀版本范围 |
|
只包含与 将版本声明为 |
|
|
匹配具有指定状态的最高版本。请参阅 ComponentMetadata.getStatus()。 |
Maven |
|
表示一个快照版本。 |
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.1
,1-a+1
,1.a-1
和1a1
是等价的。(注意:在冲突解决期间存在例外)。
-
-
比较等价部分
-
数字 vs. 数字: 数值越大,版本越高:
1.1 < 1.2
。 -
数字 vs. 非数字: 数字部分高于非数字部分:
1.a < 1.1
。 -
非数字 vs. 非数字: 部分按字母顺序和区分大小写进行比较:
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
。 -
rc
,snapshot
,final
,ga
,release
和sp
高于任何其他字符串部分,顺序如下: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
。
-
声明富版本
当你使用简写符号声明版本时,该版本被视为所需版本
dependencies {
implementation("org.slf4j:slf4j-api:1.7.15")
}
dependencies {
implementation('org.slf4j:slf4j-api:1.7.15')
}
这意味着最低版本将是 1.7.15
,并且可以被引擎乐观地升级。
为了强制使用严格版本,并确保只使用依赖项的指定版本,即使其他版本通常兼容也会被拒绝
dependencies {
implementation("org.slf4j:slf4j-api") {
version {
strictly("[1.7, 1.8[")
prefer("1.7.25")
}
}
}
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
-
这是最弱的版本声明。它仅在未指定更强的非动态版本时适用。
该术语不支持动态版本,可以补充
strictly
或require
。定义后,它会覆盖任何先前的
prefer
声明,并清除已在该依赖项上声明的任何先前的reject
。
此外,还有一个术语不在此层级结构中
reject
-
该术语指定了模块不接受的版本,如果选择到被拒绝的版本,将导致依赖解析失败。
支持动态版本。
富版本声明通过依赖或约束声明上的 version
DSL 方法访问,该方法使你可以访问 MutableVersionConstraint
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")
}
}
}
}
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'
}
}
}
}
为了强制使用严格版本,你也可以使用 !!
符号
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")
}
}
}
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.0, 2.0[ |
1.5 |
|
||
已用 |
[1.0, 2.0[ |
1.5 |
|
||
与上同,已知 |
[1.0, 2.0[ |
1.5 |
1.4 |
|
|
无意见,与 |
1.5 |
如果无其他意见则选择 |
|||
无意见,优先选择最新发布版本。 |
|
构建时最新的发布版本。 |
|||
处于边缘,最新发布版本,不降级。 |
|
构建时最新的发布版本。 |
|||
除 1.5 外无其他版本。 |
1.5 |
1.5,如果存在其他 |
|||
仅限 |
[1.5,1.6[ |
最新的 |
在库中使用 strictly
需要仔细考虑,因为它会影响下游使用者。但是,如果使用得当,它可以帮助使用者了解哪些库组合在他们的上下文中可能不兼容。更多详情,请参阅关于覆盖依赖版本的部分。
富版本信息在 Gradle 模块元数据格式中得到保留。但是,将此信息转换为 Ivy 或 Maven 元数据格式时会丢失信息。最高优先级的版本声明—— |
强调严格版本
Gradle 通过选择依赖图中最新的版本来解决任何依赖版本冲突。某些项目可能需要偏离默认行为,强制使用依赖项的更早版本,例如如果项目的源代码依赖于某个依赖项的旧 API,而一些外部库依赖于新 API。
通常,强制依赖用于降级依赖项。降级依赖项的常见用例包括:
-
在最新发布版本中发现了一个错误。
-
你的代码依赖于与新版本不二进制兼容的旧版本。
-
你的代码不使用该库中需要较新版本的部分。
强制使用某个依赖版本需要仔细考虑,因为更改传递性依赖的版本可能会导致外部库期望不同版本而引发运行时错误。如果可能的话,通常最好升级你的源代码以与新版本兼容。 |
假设一个项目使用HttpClient
库进行 HTTP 调用。HttpClient
会引入 Commons Codec
作为版本为 1.10
的传递性依赖。然而,该项目的生产源代码需要 Commons Codec
1.9
中的一个 API,而该 API 在 1.10
中已不再可用。可以在构建脚本中将其声明为 strict
来强制使用该依赖版本。
dependencies {
implementation("org.apache.httpcomponents:httpclient:4.5.4")
implementation("commons-codec:commons-codec") {
version {
strictly("1.9")
}
}
}
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
可以说,它严格依赖于 [1.0, 2.0[
范围,但优先选择 1.0
,而不是 strictly 1.0
。这样,如果消费者选择了 1.1
(或范围内的任何其他版本),构建将不再失败。
不声明版本
对于大型项目,建议不声明依赖的版本,而是使用平台来管理版本
dependencies {
implementation("org.springframework:spring-web")
}
dependencies {
constraints {
implementation("org.springframework:spring-web:5.0.2.RELEASE")
}
}
dependencies {
implementation 'org.springframework:spring-web'
}
dependencies {
constraints {
implementation 'org.springframework:spring-web:5.0.2.RELEASE'
}
}
这种方法集中管理版本,包括传递性依赖。
声明动态版本
在许多情况下,你可能需要使用特定模块依赖的最新版本或某个版本范围内的最新版本。这在开发过程中或创建需要兼容各种依赖版本的库时经常需要。项目可能采用更积极的方式来使用依赖项,通过始终集成最新版本来访问尖端特性。
你可以通过使用动态版本轻松管理这些不断变化的依赖项。动态版本可以是版本范围(例如 2.+
)或最新可用版本的占位符(例如 latest.integration
)
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.+'
}
使用动态版本和可变模块可能导致构建不可重现。随着模块新版本的发布,其 API 可能与你的源代码不兼容。因此,请谨慎使用此特性。
声明可变版本
团队在发布应用程序或库的新版本之前,可能会实现一系列特性。一种允许使用者尽早集成未完成 artifact 的常见策略是发布带有可变版本的模块。可变版本表示特性集仍在积极开发中,尚未发布稳定版本供普遍使用。
在 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 足够灵活,可以将任何版本视为可变版本。你只需将属性 ExternalModuleDependency.setChanging(boolean) 设置为 true
。