【问题标题】:How Maven and Java handle duplicated dependencies [closed]Maven 和 Java 如何处理重复的依赖项
【发布时间】:2021-02-13 19:35:01
【问题描述】:

我的应用程序中确实存在一些随机问题。而且我怀疑问题可能来自外部依赖项。让我详细说明。

我的应用程序正在使用带有请求类的外部 jar。在我的一个项目中,我添加了这个库的最新版本。但正如您可能怀疑的那样,我有更多的依赖项而不仅仅是一个。不幸的是,其中一个依赖项具有我已经添加的相同库,但版本较旧。所以此刻,当我触发mvn dependecy:tree 时,简化后的结果是这样的:

+-my_project
    +-request_lib.jar:1.5.0
    +-required_lib.jar:1.0.0
        +-random.jar:1.0.0
        +-request_lib.jar:1.2.0
        //more libs
    //more libs

如您所见,我需要的是最新版本的request_lib.jar:1.5.0,而此时没有人可以更新required_lib.jar:1.0.0,并在其中更改版本或请求。

Java 如何处理这种情况?假设在这个项目内部,我正在使用请求GetPlayerDataRequest,并且在最新版本中,有人为此添加了一个名为String playerTitle 的新字段。 Java 会一直使用最新版本的类吗?还是会混在一起?

因为据我所见,有时用户会出现致命错误,在日志中我们可以发现 setPlayerData 方法不存在。我知道我可以排除 pom 中的旧罐子。但是我想知道Java是如何处理的。

【问题讨论】:

  • 您询问的是 Maven 和 Java,但这是两个不同的问题。 Java 本身很乐意允许(假设您不使用 Java 模块系统)具有相同包和类的多个库。它将简单地从在类路径中遇到的第一个库中加载类,并且该顺序将取决于类路径的指定和组合方式。另一方面,Maven 将解析为库的单个版本(假设它们都具有相同的 groupId 和 artifactId 并且版本不同),甚至在它开始发挥作用之前。你真正感兴趣的部分是什么?

标签: java maven


【解决方案1】:

您想使用 Maven 的 <dependencyManagement> 功能。这是 Maven 中最容易被误解和poorly documented 的领域之一,也是它最强大的功能之一。

在您的pom.xml 中,如果您有一个<dependencyManagement><dependencies> 部分,那么它的任何子项都将一直应用到依赖关系树下,而不管其他位置可以指定该依赖项。 (您还可以包含不存在的条目;如果它们指定了一个您实际上并未在任何地方使用的依赖项或您的任何传递依赖项,那么它们将被忽略。)

因此,例如,如果您想确保在项目中的任何地方都使用以下依赖项,无论它是如何“拉入”或由谁“拉入”的:

<dependency>
  <groupId>com.foo</groupId>
  <artifactId>bar</artifactId>
  <version>32</version>
</dependency>

...那么,如果您将该条目添加到您的 pom.xml&lt;dependencyManagement&gt;&lt;dependencies&gt; 部分 - 即使您的项目本身不使用它,但您的传递依赖项使用它 - 所以它看起来像这样:

<dependencyManagement>
  <dependencies>

    <!-- other entries might go here -->

    <!-- force version 32 of com.foo:bar no matter how it gets pulled into your project -->
    <dependency>
      <groupId>com.foo</groupId>
      <artifactId>bar</artifactId>
      <version>32</version>
    </dependency>

    <!-- other entries might go here -->

  </dependencies>
</dependencyManagement>

...那么就可以解决问题了。

在任何地方都没有准确记录的相关事情是:“常规”&lt;dependencies&gt; 条目中的依赖版本(所以&lt;dependency&gt; 元素不显示为&lt;dependencyManagement&gt;&lt;dependencies&gt; 的子元素,但仅作为&lt;dependencies&gt; 的子元素)是建议。它们仅在覆盖 &lt;dependencyManagement&gt; 条目不存在时使用(当然,很多时候它不存在)。

【讨论】:

    【解决方案2】:

    Maven 应用了一个依赖中介机制,保证两个版本的依赖中只有一个被捆绑。所以,在这种情况下,Java 并不需要真正处理任何事情。

    相关文档:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

    【讨论】:

    • 嗯,好的。我可以在编译阶段使用最接近的 jar 来理解 maven。但是运行时呢?我们仍然捆绑了多个 jar 版本?
    • 只有 Maven 在构建过程中选择的 jar 在运行时可用。
    • 您的项目需要依赖项 A v1.0 和依赖项 B。而依赖项 B 又需要不同版本的依赖项 A (v2.0)。您的项目使用您在 pom.xml 中明确请求的依赖项 A 进行编译,而依赖项 B 在发布到 Maven Central 之前使用依赖项 A v2.0 进行了编译。运行项目后,只有依赖项 A v1.0 中的 API 可用,并且 A v1.0 和 v2.0 之间的任何重大更改都可能导致运行时错误,正是因为 B 指的是 A v2.0 而 A v2 .0 不存在。这就是它的全部。
    【解决方案3】:

    Java 允许您使用类加载器加载同一类的不同版本。

    使用您的示例,您将使用一个类加载器从 request_lib.jar 加载类,并从另一个类加载器加载 required_lib.jar。

    这个话题对于stackoverflow的回答来说太广泛了,网上有很多教程。

    【讨论】:

      猜你喜欢
      • 2018-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 2017-09-20
      • 1970-01-01
      相关资源
      最近更新 更多