Gradle 提供了工具来导航依赖项管理的结果,让你更精确地了解 Gradle 如何以及为何解析依赖项。你可以渲染完整的依赖图,识别给定依赖项的来源,并查看为何选择了特定版本。依赖项可以来自构建脚本声明或传递性关系。

要可视化依赖项,可以使用

  • dependencies 任务

  • dependencyInsight 任务

  • 一个 构建扫描

使用 dependencies 任务列出项目依赖项

Gradle 提供了内置的 dependencies 任务,用于从命令行渲染依赖树。默认情况下,该任务显示 单个项目 内所有 配置 的依赖项。依赖树显示每个依赖项的选定版本,并提供冲突解决信息。

dependencies 任务对于分析传递性依赖项特别有用。构建文件列出了直接依赖项,而该任务可帮助你了解在构建过程中解析了哪些传递性依赖项。

$ ./gradlew dependencies

理解输出注解

$ ./gradlew :app:dependencies

> Task :app:dependencies

------------------------------------------------------------
Project ':app'
------------------------------------------------------------

annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies

compileClasspath - Compile classpath for source set 'main'.
\--- com.fasterxml.jackson.core:jackson-databind:2.17.2
     +--- com.fasterxml.jackson.core:jackson-annotations:2.17.2
     |    \--- com.fasterxml.jackson:jackson-bom:2.17.2
     |         +--- com.fasterxml.jackson.core:jackson-annotations:2.17.2 (c)
     |         +--- com.fasterxml.jackson.core:jackson-core:2.17.2 (c)
     |         \--- com.fasterxml.jackson.core:jackson-databind:2.17.2 (c)
     +--- com.fasterxml.jackson.core:jackson-core:2.17.2
     |    \--- com.fasterxml.jackson:jackson-bom:2.17.2 (*)
     \--- com.fasterxml.jackson:jackson-bom:2.17.2 (*)

...

dependencies 任务使用以下注解标记依赖树

  • (*): 表示传递性依赖子树的重复出现。Gradle 每个项目只扩展一次传递性依赖子树;重复出现时只显示子树的根节点,后跟此注解。

  • (c): 此元素是依赖项约束,而不是依赖项。请在树中其他位置查找匹配的依赖项。

  • (n): 无法解析的依赖项或依赖项配置。

指定依赖项配置

要专注于特定的依赖项配置,请使用可选的 --configuration 参数。

类似于项目和任务名称,Gradle 允许使用依赖项配置的缩写名称。例如,只要能匹配唯一的配置,你可以使用 tRC 代替 testRuntimeClasspath

以下示例显示了 Java 项目中 testRuntimeClasspath 配置的依赖项

$ gradle -q dependencies --configuration testRuntimeClasspath
$ gradle -q dependencies --configuration tRC

要查看项目中的所有配置列表,包括插件提供的配置,请运行 resolvableConfigurations 报告。有关更多详细信息,请参阅插件文档,例如 Java 插件文档此处

查看示例

考虑一个使用 JGit 库执行版本发布过程中的源代码管理 (SCM) 操作的项目。你可以借助自定义依赖项配置来声明外部工具的依赖项。这避免了污染其他上下文,例如生产源代码的编译类路径。

以下示例声明了一个名为 scm 的自定义依赖项配置,其中包含 JGit 依赖项

build.gradle.kts
configurations {
    create("scm")
}

dependencies {
    "scm"("org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r")
}
build.gradle
configurations {
    scm
}

dependencies {
    scm 'org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r'
}

使用以下命令查看 scm 依赖项配置的依赖树

$ gradle -q dependencies --configuration scm

------------------------------------------------------------
Root project 'dependencies-report'
------------------------------------------------------------

scm
\--- org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r
     +--- com.jcraft:jsch:0.1.54
     +--- com.googlecode.javaewah:JavaEWAH:1.1.6
     +--- org.apache.httpcomponents:httpclient:4.3.6
     |    +--- org.apache.httpcomponents:httpcore:4.3.3
     |    +--- commons-logging:commons-logging:1.1.3
     |    \--- commons-codec:commons-codec:1.6
     \--- org.slf4j:slf4j-api:1.7.2

A web-based, searchable dependency report is available by adding the --scan option.

使用 dependencyInsight 任务识别选定的版本

一个项目可能会直接或传递地请求同一依赖项的两个不同版本,这可能导致版本冲突

以下示例引入了与 commons-codec:commons-codec 的冲突,它既作为直接依赖项添加,也作为 JGit 的传递性依赖项添加

build.gradle.kts
repositories {
    mavenCentral()
}

configurations {
    create("scm")
}

dependencies {
    "scm"("org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r")
    "scm"("commons-codec:commons-codec:1.7")
}
build.gradle
repositories {
    mavenCentral()
}

configurations {
    scm
}

dependencies {
    scm 'org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r'
    scm 'commons-codec:commons-codec:1.7'
}

Gradle 提供了内置的 dependencyInsight 任务,用于从命令行渲染依赖项洞察报告

依赖项洞察提供了关于单个配置中单个依赖项的信息。给定一个依赖项,你可以识别其版本选择的原因和来源。

dependencyInsight 接受以下参数

--dependency <dependency> (强制)

要调查的依赖项。你可以提供完整的 group:name,或其中的一部分。如果匹配多个依赖项,Gradle 将生成包含所有匹配依赖项的报告。

--configuration <name> (强制)

解析给定依赖项的依赖项配置。对于使用Java 插件的项目,此参数是可选的,因为该插件提供了默认值 compileClasspath

--single-path (可选)

只渲染到该依赖项的单个路径。

--all-variants (可选)

渲染所有变体的信息,而不仅仅是选定的变体。

以下代码片段演示了如何对 scm 配置中名为 commons-codec 的依赖项的所有路径运行依赖项洞察报告

$ gradle -q dependencyInsight --dependency commons-codec --configuration scm
commons-codec:commons-codec:1.7
  Variant default:
    | Attribute Name    | Provided | Requested |
    |-------------------|----------|-----------|
    | org.gradle.status | release  |           |
   Selection reasons:
      - By conflict resolution: between versions 1.7 and 1.6

commons-codec:commons-codec:1.7
\--- scm

commons-codec:commons-codec:1.6 -> 1.7
\--- org.apache.httpcomponents:httpclient:4.3.6
     \--- org.eclipse.jgit:org.eclipse.jgit:4.9.2.201712150930-r
          \--- scm

A web-based, searchable dependency report is available by adding the --scan option.

理解选择原因

依赖项洞察报告的“选择原因”部分列出了选择某个依赖项的原因。

原因 含义

(不存在)

除了存在直接或传递的引用之外,没有其他原因。

已请求:<文本>

依赖项出现在图中,并且包含时带有because 文本

已请求:不匹配版本 <版本列表>

依赖项以动态版本出现,其中不包含列出的版本。后面可能跟有 because 文本。

已请求:拒绝版本 <版本列表>

依赖项以丰富版本出现,其中包含一个或多个 reject。后面可能跟有 because 文本。

通过冲突解决:在版本 <版本列表> 之间

依赖项多次出现,带有不同的版本请求。这导致了冲突解决以选择最合适的版本。

通过约束

依赖项约束参与了版本选择。后面可能跟有 because 文本。

通过祖先依赖

存在一个带有 strictly丰富版本,强制使用此依赖项的版本。

通过规则选择

依赖项解析规则覆盖了默认选择过程。后面可能跟有 because 文本。

拒绝:版本 <版本> 通过规则,原因 <文本>

一个 ComponentSelection.reject 拒绝了给定版本的依赖项。

拒绝:版本 <版本>:<属性信息>

依赖项具有动态版本,并且某些版本与请求的属性不匹配。

强制

构建通过强制平台或解析策略强制使用该依赖项的版本。

如果存在多个选择原因,洞察报告会列出所有原因。

使用构建扫描获得整体视图

构建扫描中的依赖树显示了有关冲突的信息。

上述 commons-codec 示例创建了一个构建扫描,并提供了包含结果的 URL。

前往 Dependencies 选项卡,然后导航到你所需的依赖项。选择 Required By 选项卡以查看依赖项的选择原因和来源

dependency management dependency insight report build scan

解决不安全的配置解析错误

解析配置可能会对 Gradle 的项目模型产生副作用,因此 Gradle 需要管理对每个项目配置的访问。配置可能会以多种方式被不安全地解析。Gradle 会为每次不安全访问生成弃用警告。这些都是不良实践,可能导致奇怪和不确定的错误。

如果你的构建有不安全访问的弃用警告,则需要修复它。

例如

  • 一个项目的任务在其操作中直接解析另一个项目的配置。

  • 一个任务将另一个项目的配置指定为输入文件集合。

  • 一个项目的构建脚本在评估期间解析另一个项目的配置。

  • 项目配置在 settings 文件中解析。

在大多数情况下,可以通过在另一个项目上创建跨项目依赖项来解决此问题。有关更多信息,请参阅在项目之间共享输出的操作指南。

如果你发现无法使用这些技术解决的用例,请遵循我们的问题指南在 GitHub 上提交一个问题告诉我们。