首页 > 解决方案 > Maven 依赖项以及它们在 Java 项目中的实际工作方式

问题描述

我在谷歌上寻找这些答案,但找不到我的问题的确切答案,通常只是对 Maven 和 pom 和生命周期阶段的概述。我的确切问题是:

  1. 传递依赖。假设我有一个名为“Project-A”的主要 Java 项目,并且它有另一个项目作为其依赖项,例如一个具有所有 CRUD 方法的数据库 Java 项目,称为“Dependency-X”,其spring-boot-starter-jpa-1.X.X版本列在其聚甲醛。现在说我也spring-boot-starter-jpa-2.X.X 直接在 Java Project-A 的 POM 中声明(注意版本)。如果我正确理解传递依赖项,spring-boot-starter-jpa-1.XX(来自 Dependency-X db 项目)将通过 Dependency-X (db) 项目传递(间接)导入。那么哪个依赖会获胜?哪个被进口?由于它们是两个不同的版本,这显然是一个问题。您是否必须明确添加<exclusion>标记到您的 POM 中的所有依赖项,这些依赖项拉入与您的项目当前依赖项冲突的其他传递依赖项???

IE 在此处输入图像描述

  1. 多重依赖。当您在 pom.xml 中声明依赖项时,当您包含相同的依赖项两次不同版本时会发生什么;哪个被选中/导入到您的项目中,Maven 是如何决定的?而且我假设,如果 maven 在您的列表中列出的第一个 repo 中找不到这个依赖项-a <repositories>(假设您列出了超过 1 个 repo)您的 pom,它将逐个列表下去,直到它认为正确吗?IE
<dependency>
            <groupId>org.mydependency</groupId>
            <artifactId>dependency-a</artifactId>
            <version>6.6.6</version>
</dependency>
<dependency>
            <groupId>org.mydependency</groupId>
            <artifactId>dependency-a</artifactId>
            <version>8.8.8</version>
</dependency>
  1. parent-pom 到底是如何工作的?我知道我可以在其中包含<parent></parent>带有依赖项的标签,我可以单击 ctrl + B (windows) 或 command + B (mac),它将带我到 source pom (parent) 并且我可以查看所有内容。这是如何工作的——它从哪里得到这个文件?

是否所有“父”pom,例如“spring-boot-starter-jpa”依赖项实际上只是指向 maven 中央 repo 上的 POM 文件,进一步指向单个 JARS,maven 解析并导入到您的项目中???

IE

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>${spring.boot.version}</version>
</dependency>

标签: javaspringspring-bootmavendependencies

解决方案


就解决传递依赖而言,最短路径获胜。这也记录在这里

Dependency mediation - this determines what version of an artifact will be chosen when multiple versions are encountered as dependencies. Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, the first declaration wins.
"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies. Consider this tree of dependencies:
  A
  ├── B
  │   └── C
  │       └── D 2.0
  └── E
      └── D 1.0
In text, dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter.

那么哪个依赖获胜?哪个被进口?

boot starter jpa 2.x 获胜,因为它的路径最短。

对于同一依赖项的多个版本,我建议运行

mvn dependency:tree

查看包含哪一个或是否有错误。

parent-pom 到底是如何工作的?

父 pom 只是对当前项目“继承”的项目的引用。关于如何从父母那里解决依赖关系有一定的规则。在我看来,最重要的事情是,父级允许您在所有兄弟项目都可以从中继承其依赖项的地方为常见的兄弟项目添加依赖项。Spring boot 遵循这个模式来引入 starter pom 版本解析。当然,拥有父 pom 是可选的,您可以拥有一个没有父 pom 的项目。


推荐阅读