本指南解释了如何在 Gradle 中降级传递性依赖,当您的项目由于 API 兼容性、bug 或其他约束而需要旧版本时。

为什么要降级传递性依赖?

默认情况下,Gradle 通过选择依赖图中最新的版本来解决依赖版本冲突。然而,在某些情况下需要使用早期版本

  • 最新版本存在 bug

  • 您的项目依赖于与新版本不兼容的旧 API

  • 您的代码不需要需要更高版本的特性。

在降级之前,请考虑更新您的源代码以支持最新版本。

此外,您应该确保项目中没有现有的依赖约束平台版本目录将依赖设置为非期望的版本。

如果必须降级,请使用严格依赖强制依赖

选项 1:强制执行依赖的严格版本

Gradle 允许您对依赖项强制执行严格版本,确保所选版本不会被传递性依赖升级。

步骤 1:设置严格版本

假设一个项目依赖于 HttpClient,它引入了 Commons Codec 1.10,但您的项目需要 Commons Codec 1.9

dependencies.out
> Task :dependencies

------------------------------------------------------------
Root project 'how_to_downgrade_transitive_dependencies'
------------------------------------------------------------

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.apache.httpcomponents:httpclient:4.5.4
|    +--- org.apache.httpcomponents:httpcore:4.4.7
|    +--- commons-logging:commons-logging:1.2
|    \--- commons-codec:commons-codec:1.10
\--- commons-codec:commons-codec -> 1.10

您可以通过设置严格版本约束来强制执行所需的版本

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")
        }
    }
}

运行 ./gradlew dependencies --configuration runtimeClasspath 可以展示结果

dependencies-downgrade.out
> Task :dependencies

------------------------------------------------------------
Root project 'how_to_downgrade_transitive_dependencies'
------------------------------------------------------------

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.apache.httpcomponents:httpclient:4.5.4
|    +--- org.apache.httpcomponents:httpcore:4.4.7
|    +--- commons-logging:commons-logging:1.2
|    \--- commons-codec:commons-codec:1.10 -> 1.9
\--- commons-codec:commons-codec:{strictly 1.9} -> 1.9

关于严格版本的重要注意事项

  • 严格版本的行为类似于强制,这意味着它会覆盖传递性依赖。

  • 如果其他依赖项需要更高的版本,Gradle 将会失败并出现解析错误。

  • 使用版本范围而不是绝对严格版本以提供灵活性。

步骤 2:设置严格版本范围

除了锁定到单个版本,还可以定义一个严格范围

build.gradle.kts
dependencies {
    implementation("commons-codec:commons-codec") {
        version {
            strictly("[1.9,2.0[")  // Allows versions >=1.9 and <2.0
            prefer("1.9")  // Prefers 1.9 but allows newer versions in range
        }
    }
}
build.gradle
dependencies {
    implementation("commons-codec:commons-codec") {
        version {
            strictly("[1.9,2.0[")  // Allows versions >=1.9 and <2.0
            prefer("1.9")  // Prefers 1.9 but allows newer versions in range
        }
    }
}

如果其他依赖项需要 1.10,只要它在指定范围内,Gradle 就可以解析它而不会失败。

dependencies-extra.out
> Task :dependencies

------------------------------------------------------------
Root project 'how_to_downgrade_transitive_dependencies'
------------------------------------------------------------

runtimeClasspath - Runtime classpath of source set 'main'.
+--- org.apache.httpcomponents:httpclient:4.5.4
|    +--- org.apache.httpcomponents:httpcore:4.4.7
|    +--- commons-logging:commons-logging:1.2
|    \--- commons-codec:commons-codec:1.10 -> 1.9
\--- commons-codec:commons-codec:{strictly [1.9,2.0[; prefer 1.9} -> 1.9

选项 2:在配置层面强制指定版本

如果严格依赖限制性过强,您可以使用 resolutionStrategy.force() 为整个配置强制指定特定版本。

步骤 1:为整个构建强制指定版本

build.gradle.kts
configurations {
    compileClasspath {
        resolutionStrategy.force("commons-codec:commons-codec:1.9")
    }
}

dependencies {
    implementation("org.apache.httpcomponents:httpclient:4.5.4")
}
build.gradle
configurations {
    compileClasspath {
        resolutionStrategy.force("commons-codec:commons-codec:1.9")
    }
}

dependencies {
    implementation("org.apache.httpcomponents:httpclient:4.5.4")
}

运行 ./gradlew dependencies --configuration compileClasspath 可以展示结果

dependencies-config.out
> Task :dependencies

------------------------------------------------------------
Root project 'how_to_downgrade_transitive_dependencies'
------------------------------------------------------------

compileClasspath - Compile classpath for source set 'main'.
\--- org.apache.httpcomponents:httpclient:4.5.4
     +--- org.apache.httpcomponents:httpcore:4.4.7
     +--- commons-logging:commons-logging:1.2
     \--- commons-codec:commons-codec:1.10 -> 1.9

这确保了始终使用 Commons Codec 1.9,即使传递性依赖请求了更新的版本。

总结

回顾这两种选项

方法 行为

1. 严格版本 (strictly())

该版本被强制执行,但如果存在冲突,可能会触发解析失败。

2. 强制版本 (force())

该版本在配置层面被强制应用,覆盖所有其他约束。

总结如下

  • 如果您需要强制使用旧版本并希望控制兼容性,请使用严格版本

  • 使用带有首选版本的版本范围以获得一定的灵活性。

  • 当您需要在没有严格约束的情况下覆盖传递性依赖时,请在配置层面使用 force()