【问题标题】:Maven dependency within dependency with different scope具有不同范围的依赖项中的 Maven 依赖项
【发布时间】:2009-09-08 23:36:56
【问题描述】:

假设我在如下项目中定义了两个 Maven 依赖项。

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.3.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mycompany.library</groupId>
        <artifactId>mylibrary</artifactId>
        <version>1.0.1</version>
        <scope>compile</scope>
    </dependency>

然后,在 mylibrary 中,我还定义了一个依赖项,如下所示。

    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.3.1</version>
        <scope>compile</scope>
    </dependency>

当我打包我的项目时,我没有看到其中打包了 xstream。我认为项目的 xstream 依赖范围“test”覆盖了 mylibrary 的 xstream 依赖范围“compile”。

在这种情况下,为整个项目包含 xstream 以便子模块在项目中打包时可以访问它的最佳方式是什么?

我已经阅读了 Apache Maven 网站关于传递依赖的解释,但我很难理解它的含义,也很难找到在这种情况下的最佳实践。

【问题讨论】:

    标签: java maven-2


    【解决方案1】:

    这对我来说真的很奇怪,如果它是“功能”,我认为这是一个非常危险的功能。 无论如何,这不是 Maven 错误,它在 Maven 文档here 中。

    关于这个问题的最佳实践,我还没有听说过,但最安全的方法应该是完全从你的 pom 中删除 xstream,依赖传递依赖。如果删除对 mylibrary 的依赖,这样做将导致构建失败。这将作为通知您需要修复某些内容。您不会默默地丢失所需的依赖项,也不会默默地拥有不再需要的依赖项。

    附带说明,mvn dependency:analyze 可用于检查包含但未使用的依赖项。

    【讨论】:

      【解决方案2】:

      正如 mattb 的回答所说,将依赖项声明为 test 范围会覆盖传递的编译范围依赖项声明,因此该依赖项不包含在打包的战争中。

      如果您只需要测试中的依赖项,因为“mylibrary”需要它来执行,那么您不应该在项目的 pom.xml 中声明依赖项根本。让传递依赖解析过程处理它。

      如果您的项目确实直接使用 xstream jar,您仍然可以依赖传递依赖项,因为您需要为您的项目和“mylibrary”兼容的版本才能针对 xstream jar 运行。您应该进行单元测试来执行该功能,如果 mylibrary 将 xstream 的版本更改为不兼容的版本,您的构建应该会失败,此时您可以解决该问题。

      一般我会说你应该尽量避免在多模块项目中直接声明依赖版本。我在父 POM 的 dependencyManagement 部分中声明版本,以便子级只需要声明 groupId/artifactId。或者,从 Maven 2.0.9 开始,有一个额外的依赖范围 import:

      此范围仅用于该部分中 pom 类型的依赖项。它指示应将指定的 POM 替换为该 POM 部分中的依赖项。由于它们被替换,具有导入范围的依赖项实际上并不参与限制依赖项的传递性。

      因此,使用导入范围,您可以在单个 POM 中定义常用依赖项版本,将该 POM 的依赖项导入到您的 dependencyManagement 部分,然后在其他 POM 中声明依赖项的 groupId/artifactId。

      【讨论】:

        【解决方案3】:

        通过声明您自己对 xstream 的依赖并将范围设置为测试,您将覆盖 mylibrary 声明的依赖。

        这实际上是一个 Maven 特性——它允许你做一些事情,比如在你自己的项目中依赖一个传递依赖的更高版本,而不是最终打包同一个工件的两个不同版本。例如,您可能依赖于 log4j 的版本 1.2.15,但是因为您还使用依赖于 log4j-1.2.14 的 libraryX - 您不希望将 log4j-1.2.15 和 log4j-1.2.14 都打包到您的项目中。

        如果您确实希望将 xstream 打包到您的项目中,则不应将范围声明为 test。事实上,如果你删除你列出的对 xstream 的依赖,事情就会如你所愿,因为mylibrary 对它有编译依赖..

        【讨论】:

        • 在这种情况下,如果将来某个时间,我不需要使用 mylibrary 或者该库将其对 xstream 的依赖更改为其他内容,我的项目将无法通过测试。然后,我需要再次为项目的测试范围指定 xstream。这是 Maven 功能/限制吗?我愿意接受 Maven 的限制,只是想看看最佳实践是什么。
        • 我不确定这是否正确。有一种更直观的机制可以排除不需要的传递依赖,这就是 块。
        • "如果将来某个时候,我不需要使用 mylibrary 或者该库将其对 xstream 的依赖更改为其他内容,我的项目将无法通过测试。"然后在这一点上简单地添加依赖项。只要您继续依赖同一个版本的 mylibrary,就不会发生意外的变化。您的项目的新版本可能有不同的需求 - 这是完全正常的。
        【解决方案4】:

        如果你想把它打包,你为什么要声明范围?如果在编译和执行时需要它,您不应该将范围留空吗?如果你这样做了,那么你只需要

        <dependency>
            <groupId>mycompany.modules</groupId>
            <artifactId>submodule</artifactId>
            <version>1.0.1</version>
        </dependency>
        

        在你的 pom.xml 中。除非有理由在编译期间而不是在打包期间取消范围?

        【讨论】:

        • 来自 Apache Maven 网站: - compile 这是默认范围,如果未指定则使用。编译依赖项在项目的所有类路径中都可用。此外,这些依赖项会传播到相关项目。
        • 也许我最初的问题引起了混乱,因为我使用了“子模块”。请参阅上面我编辑的问题。
        猜你喜欢
        • 2018-09-21
        • 2016-05-28
        • 1970-01-01
        • 1970-01-01
        • 2013-05-17
        • 2018-07-30
        • 2013-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多