12

我为这篇文章的长度表示歉意,但我在不展示图片的情况下无法使其更简洁。我最近接手了一个 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 可能位于 path 中c:\dev\MyEarProject\module1,但具有 artifact name hibernate-module。但是,由于它在 RTC 中的存储方式,在module1签出时会调用该目录。

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

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

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

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

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

4

3 回答 3

12

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

  +-- 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's ,它将在发布阶段被发布插件取代。与此相关,它将自动更改相应父母等中的所有版本。

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

<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从该文件夹执行操作,一切都会变得更简单。

于 2012-05-04T16:57:22.877 回答
2

如果要发布 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 相同的名称很有用。

于 2012-05-04T16:30:11.557 回答
2

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

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

祝你的项目好运。

于 2012-05-04T19:20:40.870 回答