【问题标题】:Force Maven use only first level dependencies强制 Maven 仅使用第一级依赖项
【发布时间】:2013-10-23 08:25:59
【问题描述】:

我有一个 Maven Java 项目。我不希望在编译项目时通过一系列子依赖项偶然满足我的项目依赖项。当 maven 必须检查所有使用的依赖项并将必要的库添加到 war 时,我在构建最终战争时没问题,但是在编译代码时,我想确保只使用直接依赖项。为什么?

假设我有两个依赖项:

<dependency>
    <groupId>com.package</groupId>
    <artifactId>module-1</artifactId>
</dependency>

<dependency>
    <groupId>com.package</groupId>
    <artifactId>module-2</artifactId>
</dependency>

对于我们的项目,module-1 和 module-2 的用途完全不同,但是在 module-2 的依赖树的某个地方,使用了 module-1。我删除了 module-1 依赖项,但 maven 继续构建我的项目而没有编译错误,因为它从 module-2 子依赖项中解析了 module-1。这种变化被忽视了。

一段时间后,我们决定删除 module-2,因为我们不需要它。很奇怪,但我们不能再编译使用从模块 1 导入且未连接到模块 2 逻辑的类。

这是一个简单的案例,但在大型项目中,这可能会使依赖关系变得非常混乱。

【问题讨论】:

    标签: java maven dependencies


    【解决方案1】:

    您可以使用Maven dependency plugin 目标“dependency:analyze”为您提供所有未在当前模块上声明的已使用依赖项的报告(包括传递性)。这样 Maven 仍然会使用传递依赖(我猜没有办法),但你可以通过插件强制自己确保这些也被声明。它还会警告你不必要的依赖。请注意,该插件会分析已编译的类。有时,您可能需要配置插件,因为有时它可能在编译时检测不到依赖项,但在运行时检测不到,例如因为内联了一个常量。

    【讨论】:

    • 很酷的功能 :) 还是不明白,为什么 maven 允许使用间接依赖进行编译。为什么有人会使用间接解析库中的类,而大多数时候你不知道也不需要知道这个库。它们由您引用的模块在内部使用,并且仅在您构建最终可运行模块时才需要。
    • 这不是错误,而是一项功能。实际上,传递依赖特性是很多人使用 Maven(或 Ivy,或 Groove Grapes 等)的主要原因之一。顺便提一句。您是否尝试使用正确的范围,例如仅在编译期间和稍后在运行时需要的依赖项“提供”的范围,但在其他情况下不需要?
    • 在很多情况下编译器需要传递依赖,即使没有代码引用它。例如,如果在模块 1 中有类 A,而在模块 2 中有扩展类 A 的类 B,则任何引用类 B 的代码也需要在构建路径上有类 A 才能编译(因此是模块 1)。因此,预测哪种传递依赖是不必要的将非常复杂。
    【解决方案2】:

    如果您确实需要这样做,那么您可以在 pom 中设置排除项。

    例如这是我的一个 pom 中的一个排除示例,我不希望它自动获取公共日志记录,因为我使用的是不同的日志记录提供程序。

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
        </dependency>
    

    你可以做这样的事情(未经测试)

    <dependency>
        <groupId>com.package</groupId>
        <artifactId>module-2</artifactId>
        <exclusions>
          <exclusion>
            <groupId>com.package</groupId>
            <artifactId>module-1</artifactId>
          </exclusion>
        </exclusions>
    </dependency>
    

    不过,我不一定会推荐这个。在我的日志排除的情况下这是有道理的,因为我使用的是 slf4j 而不是公共日志。如果整个项目都使用 spring 3,我已经看到了其他示例,这些示例用于排除 spring 2。

    从您的示例中很难分辨,因为它太模糊了。通常,您应该将依赖项保持在最低限度。如果 module-2 依赖于 module-1,那么这意味着您的应用程序在没有 module-1 的情况下将无法编译或运行。如果事实上没有它它可以幸福地生活,那么它并不是真正的依赖。

    附带说明,您没有针对依赖项的版本号,这有点令人担忧。你可能会发现 maven 会警告你。最好始终包含版本号。如果您依赖于当前正在开发的模块,那么您应该在版本上使用 .SNAPSHOT 后缀来获取该版本的最新构建。

    【讨论】:

    • 嗨,本,感谢您的回答。这是一个虚构的例子。实际情况要复杂得多,有 20-30 个 pom 文件。他们很快就搞砸了。
    • 听起来你需要解开它们;)
    【解决方案3】:

    似乎没有办法告诉 maven 不要传递地解决依赖关系:How to exclude all transitive dependencies of a Maven dependency。我认为原因之一是用户很快就会遇到运行时问题,当他发现某些工件在运行时没有得到解决或存在工件版本问题时。但是,如果您检查链接,则可以使用通配符排除模式使每个部门都“独立”。

    另一种选择是为每个module-X 子依赖项使用&lt;optional&gt; 依赖项。这将确保项目编译并且您的module-X 中的非将被传递解决。喜欢:

    <dependency>
       <groupId>com.package</groupId>
       <artifactId>module-1</artifactId>
       <optional>true</optional>
    </dependency>
    

    不过,分析依赖树可能是最安全和可预测的选择。

    【讨论】:

      【解决方案4】:

      你打算做什么听起来确实有点奇怪。在某种程度上,你破坏了你想要使用的依赖管理。

      如果你的 module-2 依赖于 module-1 并且对它有依赖关系,那么任何依赖于 module-2 的模块只需要定义那个。

      您可以使用排除项限制分辨率的深度:Exclude all transitive dependencies of a single dependency

      较新版本的 maven 允许在其中使用通配符。

      但是:您将需要重新添加您实际需要的那些,这是通过重复您拥有其他模块的依赖项。这重复了工作。

      如果存在导致异常的工件,可以定义一个范围:http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html,因此它也不会传播到依赖模块。

      【讨论】:

      • 感谢您的回复:您打算做什么听起来确实有点奇怪。在某种程度上,你破坏了你想要使用的依赖管理。如果你的 module-2 依赖于 module-1 并且对它有依赖关系,那么任何依赖于 module-2 的模块只需要定义那个。 - 假设 module-1 是一个核心框架模块。我的模块使用它,module-2 也使用它。
      • 那么两个模块都需要将其定义为依赖项。 (这经常被遗忘,当module-2 不再依赖于module-1 时破坏你的模块;dependency:analyze 可以帮助解决这个问题。)但这就是它的完成方式......希望有足够多的人在这里加入让你相信这是正确的方式。 Maven 有很多方法可以让自己以一种或另一种方式进行配置,这不是其中之一。如果您不想要这个,Maven 可能不适合您。然后,如果您真的坚持,dependency:copy 可能会让您继续前进,但是您会完全放弃 Maven 的依赖机制。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-06
      • 1970-01-01
      • 2022-10-04
      • 1970-01-01
      • 2014-10-13
      • 2020-08-06
      相关资源
      最近更新 更多