【问题标题】:How to restructure Maven multi-module project?如何重构 Maven 多模块项目?
【发布时间】:2012-05-14 05:04:32
【问题描述】:

对于这篇文章的长度,我深表歉意,但我在不展示图片的情况下无法使其更简洁。我最近接手了一个 maven 3.0 多模块项目的 build-master 工作。问题是项目/模块的结构是一场灾难。从当前存储在源代码控制中的方式(我们使用 RTC)到模块的 pom 结构,我都在竭尽全力尝试每次都完成一个完整的构建周期。

随着项目层次结构的发展,所有模块都“扁平”地存储;即:一切都在同一水平。我有一个父 pom,所有模块都依赖于父级。但是,父级与我所有其他模块处于同一级别。

例如:

c:\dev\MyEarProject
 + parent-pom
   - pom.xml
 + module1
   - pom.xml (depends on parent-pom)
   - src
   -   main
   -     ...
 + module2
   - pom.xml (depends on parent-pom)
   - src
   -   main
   -     ...
 + module3
   - pom.xml (depends on parent-pom)
   - src
   -   main
   -     ...

父 pom 定义了构建项目所需的所有模块,以及在不同子模块中使用的工件版本号的一堆属性:

<modules>
  <module>../module1</module>
  <module>../module2</module>
  <module>../module3</module>
</modules>

<properties>
    <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
    <slf4j.version>1.6.4</slf4j.version>
    <repositoryAddress>${snapshots.repo.url}</repositoryAddress>
    <my.hibernate-module.dao.impl>1.2.3</my.hibernate-module.dao.impl>
    <my.hibernate-module.dao.api>1.2.3</my.hibernate-module.dao.api>
</properties>

每个模块的 pom 反过来又通过 pom 的工件编号依赖于父 pom:

<parent>
    <groupId>com.cws.cs.lendingsimulationservice</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0.6</version>
</parent>

为了让事情变得更加混乱,实际的工件名称可能会也可能不会(取决于模块)与模块路径匹配。例如,module1 可能位于路径c:\dev\MyEarProject\module1,但工件名称为hibernate-module。但是,由于它在 RTC 中的存储方式,该目录在签出时称为module1

当然,构建一切的最简单方法是进入c:\dev\MyEarProject\parent-pom\ 并运行mvn clean deploy。这在 SNAPSHOT 模式下工作正常,因为 SNAPSHOT 存储库允许同一工件版本的多个部署。但是在发布模式下,这会失败。

这种结构给我带来了 2 个问题。

  1. 每次我需要对 parent 中的属性进行版本更改时,我都必须更新 parent-pom 版本号,以及所有子模块父 pom 的版本,以及所有子模块本身的版本(因为父更改)。
  2. 每当我需要部署发布周期时,如果其中一个模块自上一个周期以来没有更改并且因此无法重新部署到同一个 repo(repo 不允许覆盖现有工件),mvn 将引发错误李>

所以我正在寻找重组这个项目以避免这些问题的最佳方法。对于父 pom,我知道我可以使用相对路径来指向父级。但是,鉴于模块的“扁平”结构,这是一种推荐的方法吗(即:父 pom 相对路径将是 ../parent-pom/pom.xml - 对我来说似乎有点奇怪)?此外,鉴于父级的版本控制独立于模块,使用相对路径不仅会导致额外的混乱(即:无法知道父级 pom 的哪个版本与哪个版本相关联子模块)。

其次,如何构建整个耳朵而不会遇到我遇到的部署错误?由于工件已经存在于 repo 中,我不需要重建和重新部署它。我尝试使用 --projects,但由于涉及的模块数量众多,管理起来非常困难。

【问题讨论】:

    标签: java maven multi-module maven-deploy-plugin


    【解决方案1】:

    我真正建议的第一件事是重组项目文件夹......这意味着让项目文件夹代表结构,这意味着扁平化结构。

      +-- parent-pom (pom.xml)
           +--- module1 (pom.xml)
           +--- module2 (pom.xml)
           +--- module3 (pom.xml)
    

    因此,您的父级模块部分将被简化如下:

    <modules>
      <module>module1</module>
      <module>module2</module>
      <module>module3</module>
    </modules>
    

    此外,您的模块中的父条目也可以这样简化:

    <parent>
      <groupId>com.cws.cs.lendingsimulationservice</groupId>
      <artifactId>parent-pom</artifactId>
      <version>1.0.6</version>
    </parent>
    

    ...这让我想到了下一点:

    如果您当前的所有项目都将它们的父项定义为上述,这是完全错误的,原因将尝试在存储库中而不是在上层文件夹中查找父项。换句话说,这会导致您在发布等方面遇到很多问题。

    如果我们要解决这个问题,它必须看起来像这样,我不推荐:

    <parent>
      <groupId>com.cws.cs.lendingsimulationservice</groupId>
      <artifactId>parent-pom</artifactId>
      <version>1.0.6</version>
      <relativePath>../parent-pom/pom.xml</relativePath>
    </parent>
    

    我观察到的另一件事是您不使用SNAPTSHOT,它将在发布阶段被发布插件取代。与此相关,它会自动更改相应父母等中的所有版本。

    在理想情况下,您的模块应如下所示:

    <parent>
      <groupId>com.cws.cs.lendingsimulationservice</groupId>
      <artifactId>parent-pom</artifactId>
      <version>1.0.6</version>
    </parent>
    
    <artifactId>module-1</artifactId>
    <!-- No Version or groupId -->
    

    因为所有模块都会从它们的父模块继承版本和groupId。有时更改模块groupId 很有用或需要,但这是一个例外。

    我重读的内容是关于父级的单独版本控制。这根本没有意义,因为它是它们模块的父级,所以将它放入相同的结构,当然还有相同的 VCS。

    如果你想制作一些配置/插件版本,应该用于其他项目的依赖项,而不是制作一个单独的公司pom.xml,这是一个单独的项目,将单独发布等。

    完成结构更改后,您只需进入 parent-pom 目录并从该文件夹执行 mvn clean packagemvn release:prepare release:perform 即可,一切都会变得更简单。

    【讨论】:

    • 不幸的是,鉴于 RTC 和为此项目设置的组件/模块的方式,重组为具有树结构不是一种选择。所以我必须接受当前的结构/布局,并充分利用这种情况。将版本置于父级别以由所有子模块继承本质上意味着重建/重新测试/重新部署所有模块(这可能很昂贵),即使单个模块中只有一个更改。从本质上讲,我失去了独立版本一个模块的能力。虽然我同意;它将解决我的部署问题。
    • 如果你想继续与 maven 对抗,轮到你了,但我建议改变结构,因为它会让你的生活更轻松。但是,如果单独部署每个模块的想法没有意义。他们要么是相关的,要么是不相关的。如果它们不是那么你应该让它们真正分开并且不要使用多模块构建。
    • 我无法理解如何使用仅在父级中定义的版本号来执行此操作。在我当前的设置中,我可以在不影响构建的其余部分的情况下更改模块中的接口,直到需要重新集成新版本。仅在父版本中,更改模块的接口将破坏构建的其余部分,因为所有模块都将依赖源树而不是预部署的二进制文件。我该如何避免这个问题?我仍然需要单独对每个模块进行版本控制,不是吗?
    • 如果你真的需要单独的版本,这意味着单独的版本你需要有单独的模块而不是多模块构建。
    • 如果我们要解决这个问题,它必须看起来像这样,我不能推荐 - 那你推荐什么?
    【解决方案2】:

    您提出了相互矛盾的要求。你想重组你的项目,但不能移动。您希望简化部署和发布周期,但不想使用单一版本。

    鉴于一个模块中的更改将不可避免地影响所有依赖模块,我将使用一个简单的版本控制方案,其中所有子模块都继承其父模块的版本。 maven 发布:准备和发布周期变得简单。使用发行说明来跟踪您的更改并证明跳过对未更改模块的不必要测试是合理的(对版本的更改不会更改构建过程的构建/二进制输出,因此您可以将其用作主要参数)。

    祝你的项目好运。

    【讨论】:

      【解决方案3】:

      如果您要发布 POM,则必须发布任何更新,但无需手动修改 POM 版本 - 您可以使用版本插件或发布插件自动更新版本。我更喜欢发布插件,因为它也会为您提交 SCM。

      mvn versions:set 
      

      http://mojo.codehaus.org/versions-maven-plugin/

      mvn release:prepare release:perform
      

      http://maven.apache.org/plugins/maven-release-plugin/

      您的存储库管理器也可能允许覆盖现有版本,但最好只发布新版本。

      我更喜欢平面模块结构,因为它允许使用父文件夹来存储常见文件,例如checkstyle 配置。我还发现跨模块共享组 id 然后将模块目录命名为与 artifactId 相同的名称很有用。

      【讨论】:

      • 我已经有一段时间没有使用发布插件了,但是当我需要将单个模块升级到新版本时,我不明白它将如何解决我的问题。如果 module3 需要更新(从 1.1 升级到 1.2-SNAPSHOT),并且 module1 依赖于 module3,那么我更新 module3 pom、parent-pom 属性、parent-pom 版本、module3 父版本,最后是 module1 父版本和 module1 版本。发布插件如何为我完成所有这些工作?请注意,此时不需要 module2 进行任何更改。
      • 版本插件应该能够为您更新依赖项,然后您就可以提交和部署新的工件。
      猜你喜欢
      • 2014-05-22
      • 1970-01-01
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      • 2014-03-08
      • 2018-02-06
      • 1970-01-01
      • 2019-05-21
      相关资源
      最近更新 更多