Gradle会将传递性的运行时依赖项作为编译时依赖项包含进来。

8

我在gradle依赖管理中遇到了奇怪的行为,项目A将项目B作为编译时依赖,而项目B将库C作为运行时依赖。现在我可以在项目A中使用库C的类。

我的问题是:这是一个bug还是一个特性?

可以使用gradle 2.9和2.10以及以下最小设置来复制该问题:

// settings.gradle
include ':A', ':B'

// build.gradle
allprojects {
    apply plugin: 'java'
    apply plugin: 'maven'

    repositories {
        mavenLocal()
        mavenCentral()
    }
}

project(':A') {
    dependencies {
        compile project(':B')
    }
}

project(':B') {
    dependencies {
        runtime "org.slf4j:slf4j-log4j12:1.7.13"
    }
}

正如您所看到的,gradle :A:dependencies 显示了以下内容:

[...]

compile - Compile classpath for source set 'main'.
\--- project :B
     \--- org.slf4j:slf4j-log4j12:1.7.13
          +--- org.slf4j:slf4j-api:1.7.13
          \--- log4j:log4j:1.2.17
[...]

在项目A中使用log4j完全可以在java代码中实现。


谢谢你问这个问题,Michael。在这种情况下,Gradle的行为完全令人费解 :-( - Peti
2个回答

6

请参考这个问答。如果你没有指定配置,Gradle会选择从runtime继承的default配置。一个快速修复的方法是使用:

compile project(path: ":B", configuration: "compile")

“default”配置从“runtime”扩展,这意味着根据Q&A上的解释,“它包含所有运行时配置的依赖项和构件,以及可能更多”。项目“:B”在运行时配置中的依赖关系是“runtime”。这仍然无法解释为什么依赖项“slf4j-api”在项目“:A”中显示为“compile”。 - dmoebius
2
compile project(':B') 方法会将项目 B 的 default 配置添加到项目 A 的 compile 配置中。因此,逻辑上来说,B 的 runtime 依赖项会被添加到 A 的 compile 依赖项中。 - lance-java
3
我已经与@dmoebius在离线情况下讨论过了,虽然答案完全正确且有帮助,但应该记住以下几点:明确指定compile配置确实可以防止您的项目编译类路径被传递运行时依赖项“污染”,但是您的项目运行时类路径现在也缺少这些传递运行时依赖项。因此,您可以接受使用default配置,或者添加第二个依赖项来将runtime映射到runtimeruntime project(path: ":B", configuration: "runtime") - Michael Schaefers
在这种情况下,没有必要明确指定“runtime”配置。由于“default”扩展了“runtime”,因此您可以只使用“compile project(':B')”。 - lance-java
好的,我明白了。但是我必须说,为了获得(我认为的)正确的传递依赖行为,仅仅为每个依赖项指定compile project(path: ":B", configuration: "compile"); runtime project(':B')是至少很麻烦的。更不用说:对于新手来说完全令人困惑。 - dmoebius
1
dependencies {} 部分中的每行都配置一个单独的配置(如编译或运行时),因此在一行代码中永远不会同时配置两个配置是合乎逻辑的(至少对我来说是这样)。我希望maven的表现也是如此(例如,所有传递性的运行时/编译时依赖项添加到与声明的 <dependency> 相同的范围)。 - lance-java

1

在 Android 库 (aar) 传递运行时依赖的情况下,Gradle 从 5.0 开始修复了此问题。


我在这里解释了Gradle运行时依赖项示例:https://stackoverflow.com/a/59686732/185498 - Manushin Igor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接