当前位置: 首页 > 知识库问答 >
问题:

Maven父POM:循环依赖

徐弘图
2023-03-14

我们有一个模块化项目,包含大约10个工件:

parent
 +- artifact1
 +- artifact2
 +- artifact3
 +- ...
 +- artifact10

此外,一些工件之间存在依赖关系:

artifact1
 +-> artifact2
 +-> artifact3
 +-> ...
 +-> artifact10

artifact2
 +-> artifact3

artifact4
 +-> artifact3

artifact4
 +-> artifact5

artifact5
 +-> artifact6

我们当前的设置如下所示:

  • parent是包含父POM的工件
  • 这个父POM定义了所有必要的依赖项(比如Spring、JPA等等)进来
  • 我们所有的工件也都在中定义
  • 我们的工件将父工件称为明显的父工件
  • 只有父POM定义版本。其他所有的POM都没有

我们使用三个数字的版本控制方案:

<major version>.<minor version>.<patch level>

例如:

0.1.0-SNAPSHOT (a young artifact in development)
0.1.0 (the same artifact once it has been released)
0.1.1 (the same artifact after a hotfix)

问题是:

一旦我们更改了工件的版本(例如:0.1.0=

解决这种循环父子关系的最佳方法是什么?我们可以从父POM中删除我们自己的依赖项,并在所有其他工件的POM中定义它们的版本,但这意味着一旦依赖项发生变化,我们就需要更新所有工件。

编辑

包含我们工件的简化目录结构:

.
├── [api:0.14.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java ...
│       │   └── webapp ...
│       └── test
├── [dao:1.21.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main ...
│       └── test ...
├── [parent:0.11.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main ...
│       └── test ...
├── [pdf-exporter:0.2.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main ...
│       └── test ...
├── [docx-exporter:0.3.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main ...
│       └── test ...
├── [exporter-commons:0.9.0-SNAPSHOT]
│   ├── pom.xml
│   └── src
│       ├── main ...
│       └── test ...
└── [security:0.6.0-SNAPSHOT]
    ├── pom.xml
    └── src
        ├── main ...
        └── test ...

工件目录(在方括号中;以及工件版本)是相互独立的,也就是说,为了方便起见,它们只在一个公共根目录中 (".") 。每个工件都有自己的git存储库。“api”是部署在应用程序服务器上的工件。所有工件都像这样引用“父”(在开发过程中):

<parent>
    <groupId>com.acme</groupId>
    <artifactId>parent</artifactId>
    <version>0.11.0-SNAPSHOT</version>
</parent>

<artifactId>api</artifactId>
<version>0.14.0-SNAPSHOT</version>

情景:

  • exporter commons获得更新:0.9.0-SNAPSHOT=

问题:api:0.14.0-SNAPSHOT引用父:0.11.0-SNAPSHOT。api:0.14.0-SNAPSHOT然后更新为引用父:0.12.0-SNAPSHOT。api:0.14.0-SNAPSHOT变为api:0.15.0-SNAPSHOT。但是父:0.12.0-SNAPSHOT中的pom.xml引用了api:0.14.0-SNAPSHOT。=

(注意:工件名称是为了简单而编的。)

共有3个答案

太叔坚
2023-03-14

如果所有其他模块(“子模块”)都依赖一个公共根模块(“父模块”),则父模块不应依赖任何子模块。

这是因为Maven的工作方式非常简单:要构建一个模块,首先要构建它所依赖的所有尚未构建的模块(使用传递闭包模型)。如果你有一个循环依赖项,你最终会遇到这样的情况:为了构建一个,你必须先有一个构建的。这太疯狂了,显然不会有什么用处。

但是,也可以让父模块的子模块成为子模块。这是一种不同的、不可继承的关系,它导致子模块在超级模块之后构建。行得通。让超级模块的子模块在超级模块上除了简单的包含之外没有其他关系也是完全合理的。

简而言之,无论您以何种方式在磁盘和存储库中安排模块,都不要引入循环依赖关系。(我看到有人认为,循环依赖应该在逻辑上把一组模块变成一个模块,因为这是理智地定义适当的包含运算符的操作的唯一方法。我不确定我是否完全同意这一点,但这并不是完全错误的…)

冀俊良
2023-03-14

Maven中的一个主要混淆来源是pom实际上可以包含两种不同类型的关系:

  • 亲子关系:
    • 在其内每个子级声明一次
    • 通过

    如果所有模块都保持在同一版本上(即始终从顶层执行发布),那么这种区别就无关紧要了。但一旦版本开始分裂(即发布一个子模块而不是另一个子模块),就有必要为每个任务创建两个单独的POM。

    project/
      parent/
        parent_pom.xml      # declare dependency versions as ranges [0.1.0, 0.2.0)
      children/
        aggregator_pom.xml  # <modules> section lists api/dao/etc
        api/
          pom.xml           # declare parent_pom as parent
        dao/
          pom.xml           # declare parent_pom as parent
    

    为什么需要这种复杂的结构?

    为什么不接受MariuszS的建议,在顶级家长中使用范围?

    想象一个基本组件,比如api,非常稳定。如果可以避免,您不想重建或重新发布它。

    同时,让我们假设另外两个相互依赖的组件,比如pdf exporterdocs,您经常发布和/或分支它们,以便经常更改版本范围:0.1。x-

    然后您将被迫修改和释放您的父pom以反映pdf-exitterdocs之间的关系,但您不一定想发布api,因为它不关心这些更改。因此需要将父放在一边,并确保释放它不会触发api子模块的不必要重新发布。

武琛
2023-03-14

为了简化依赖项配置,请使用版本范围。

例如工件A需要版本0.1.0的工件B。将依赖项配置为范围

这意味着A需要版本大于或等于0.1.0且小于0.2.0的B(因此所有修补程序都适用于此工件)。

这很有帮助,因为当热修复补丁发布时,不需要更改工件A依赖项。只需重建父项目,热修复B将附加到项目A

这种技术需要在父项目发布修补程序时发布父项目,我指的是像与库或EAR的战争,或者包含所有工件的分发存档。

更多:3.4.3。依赖项版本范围

 类似资料:
  • 问题内容: 我有一个模块化的maven项目,其中两个模块“ BIZ”和“ EJB”包含如下内容: 如您所见, “ EJB”依赖于“ BIZ”, 因为它使用 MyClassX (实际上,它使用了BIZ的几种类别)。这就是 ImplFactory 使用反射实例化 InterfaceImpl 的原因。问题是 cl.newInstance() 将抛出 ClassCastException, 因为这两个模块

  • 我有一个带有子pom B、C和D的父pom A,在B、C和D中,我有相同类型的依赖项。 ie父Pom 儿童Pom 到目前为止,我已经尝试过编辑插件surefire,当试图排除子pom的测试范围时,它不起作用。 我的问题是,是否有一种方法可以将概要文件添加到父pom中,以排除所有子pom的类型测试jar的所有依赖项。谢谢

  • 使用可以用于基于的遗留用例,但也可以测试我们正在迁移的未来用例:。 我是否可以在每次修改POM时实现以下反应器构建?或者,类似的东西?或者,Maven仅仅是这个用例的错误工具吗? 理想情况下,我希望在一个反应器构建中实现所有功能,每个编译并与每个继承的依赖项一起使用。我知道这会使我的Maven repo处于不希望的状态,但至少我可以将反应器构建插入到我的CI,并确保我的构建在依赖平台上运行。 注意

  • 我想知道以下jar的所有传递依赖项: 将经典命令移动到pom。项目定义依赖关系和输入的xml: mvn依赖:树 将显示: 我没看到魔咒父母: 乍一看,mvn命令似乎可以显示非pom类型的依赖项。 有没有一种方法可以精确地显示使jar保持活动状态所需的每个文件? 谢谢

  • 如何从父POM解析占位符的托管属性?我希望它是全局解析的,因此当父pom具有版本2时,也将解析为版本2。 在父级pom中,我有: 在孩子身上我用 这是意料之中的行为吗?我使用的是maven 3.0.4。

  • 作为foo-3.0.0.jar的“旧版本圈”使用bar-2.0.0.jar,bar-2.0.0.jar使用foo-1.0.0.jar。 这不是关于构建foo.jar或bar.jar,而是关于构建依赖于foo.jar或bar.jar的项目。