Java gradle将可传递的运行时依赖项包括为编译依赖项

Java gradle将可传递的运行时依赖项包括为编译依赖项,java,gradle,dependency-management,Java,Gradle,Dependency Management,我正在体验gradle依赖项管理中的一个奇怪行为,其中项目a引用项目B作为编译依赖项,项目B引用库C作为运行时依赖项。现在我可以在我的项目A中使用库C中的类 我的问题:(为什么)这是一个bug还是一个功能? 使用gradle 2.9和2.10以及以下最小设置可以重现该问题: //settings.gradle 包括:A',':B' //build.gradle 所有项目{ 应用插件:“java” 应用插件:“maven” 存储库{ mavenLocal() mavenCentral() } }

我正在体验gradle依赖项管理中的一个奇怪行为,其中项目a引用项目B作为编译依赖项,项目B引用库C作为运行时依赖项。现在我可以在我的项目A中使用库C中的类

我的问题:(为什么)这是一个bug还是一个功能?

使用gradle 2.9和2.10以及以下最小设置可以重现该问题:

//settings.gradle
包括:A',':B'
//build.gradle
所有项目{
应用插件:“java”
应用插件:“maven”
存储库{
mavenLocal()
mavenCentral()
}
}
项目(“:A”){
依赖关系{
编译项目(':B')
}
}
项目(':B'){
依赖关系{
运行时“org.slf4j:slf4j-log4j12:1.7.13”
}
}
如您所见,显示一个渐变
: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中的java代码中使用log4j是完全可能的。

请参阅Q&A。如果不指定配置,Gradle将选择从运行时扩展的
默认
配置。快速修复方法是使用

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

对于Android库(aar)的可传递运行时依赖项,从5.0开始使用Gradle解决了这一问题。

默认的
配置扩展自
运行时
,这意味着,根据Q&A上的解释,“它包含
运行时
配置的所有依赖项和工件,可能还有更多。”运行时配置中project“:B”的依赖项是
运行时
。这仍然不能解释为什么依赖项
slf4j api
在project:A中显示为
编译
编译项目(':B')
方法从项目B获得
默认
配置,并将其添加到项目A的
编译
配置中。因此,将B的
运行时
依赖项添加到A的
编译
依赖项是合乎逻辑的。我与@dmoebius离线讨论了这一点,尽管答案完全正确且有用,应该记住以下几点:明确指定
compile
配置确实可以防止项目编译类路径被可传递的运行时依赖项“污染”,但是您的项目运行时类路径现在也缺少这些可传递的运行时依赖项。因此,您可以使用
default
正在使用配置,或者您必须添加第二个依赖项,以将
运行时
映射到
运行时
运行时项目(路径::B”,配置:“运行时”)
在这种情况下,不需要显式指定
运行时
配置。由于
默认值
扩展了
运行时
您可以使用
编译项目(':B')
依赖项{}
部分中的每一行都配置了一个配置(即编译或运行时),因此它是逻辑的(至少对我而言)您永远不会在一行代码中配置两个配置。我希望maven以相同的方式运行(例如,所有可传递的运行时/编译依赖项都添加到声明的相同范围),感谢您的提问。在这种情况下,gradle的行为完全违反直觉:-(我在这里解释了gradle运行时依赖关系示例: