Maven父POM与模块POM


284

在多项目构建中,似乎有几种构造父pom的方式,我想知道是否有人对每种方式的优点/缺点有什么想法。

具有父pom的最简单方法是将其放在项目的根目录下,即

myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

其中pom.xml既是父项目,又描述了-core -api和-app模块

下一个方法是将父级分离到其自己的子目录中,如下所示:

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/

父pom仍包含模块但相对的模块,例如../myproject-core

最后,还有一个选项,其中模块定义和父级分开,如下所示

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

父pom包含任何“共享”配置(dependencyManagement,属性等),而myproject / pom.xml包含模块列表。

目的是要可扩展到大规模构建,因此应可扩展到大量项目和工件。

一些奖励问题:

  • 在哪里定义各种共享配置的最佳位置是哪里,如源代码控制,部署目录,通用插件等。(我假设是父级,但我经常对此感到bit恼,它们最终出现在每个项目中,而不是最终出现在每个项目中一个普通的)。
  • maven-release插件,hudson和nexus如何处理您如何设置多项目(可能是一个巨大的问题,当有人通过多项目构建的方式来抓捕时,问题就更大了)?

编辑:每个子项目都有自己的pom.xml,我将其保留以保持简洁。


每个模块也都有自己的pom吗?我的项目有一个父pom,但是每个模块也都有pom。(也许是您所描述的第四种方法)
harschware 2010年

嗯,是的,我将进行编辑和更新。每个子模块也都有自己的pom。
Jamie McCrindle 2010年

3
作为一个更新,我可以看到第二个选项的一个优点是,在Eclipse中更容易管理,如果子模块是Eclipse中的单独项目,则第一个和第三个示例中的根pom.xml很难包含在内。
Jamie McCrindle

Answers:


166

我认为,要回答这个问题,您需要考虑项目生命周期和版本控制。换句话说,父pom是否有其自己的生命周期,即它可以与其他模块分开发行吗?

如果答案是肯定的(问题或评论中提到的大多数项目都是这种情况),那么父pom需要从VCS和Maven的角度来看自己的模块,最终在VCS级别具有以下内容:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
`-- projectA
    |-- branches
    |-- tags
    `-- trunk
        |-- module1
        |   `-- pom.xml
        |-- moduleN
        |   `-- pom.xml
        `-- pom.xml

这使结帐有点痛苦,并且使用来处理该结帐的常见方法svn:externals。例如,添加一个trunks目录:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks

具有以下外部定义:

parent-pom http://host/svn/parent-pom/trunk
projectA http://host/svn/projectA/trunk

然后,检出trunks将导致以下局部结构(模式2):

root/
  parent-pom/
    pom.xml
  projectA/

您也可以选择pom.xmltrunks目录中添加一个:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks
    `-- pom.xml

pom.xml是一种“伪”的pom:从不发布,它不包含真实版本,因为从不发布此文件,它仅包含模块列表。使用此文件,检出将导致此结构(模式3):

root/
  parent-pom/
    pom.xml
  projectA/
  pom.xml

这种“ hack”允许在签出后从根目录启动反应堆构建,并使事情变得更加方便。实际上,这就是我喜欢为大型构建设置Maven项目和VCS存储库的方式:它可以正常工作,可以很好地扩展,它可以提供您可能需要的所有灵活性。

如果答案是否定的(回到最初的问题),那么我认为您可以使用模式1(做可能可行的最简单的事情)。

现在,关于奖金问题:

  • 在哪里定义各种共享配置的最佳位置是哪里,如源代码控制,部署目录,通用插件等。(我假设是父级,但我经常对此感到bit恼,它们最终出现在每个项目中,而不是最终出现在每个项目中一个普通的)。

老实说,我不知道如何在这里不给出一般性的答案(例如“使用您认为有意义的层次来使事物相互关联”)。而且无论如何,子poms始终可以覆盖继承的设置。

  • maven-release插件,hudson和nexus如何处理您如何设置多项目(可能是一个巨大的问题,当有人通过多项目构建的方式来抓捕时,问题就更大了)?

我使用的设置效果很好,没有什么特别需要提及的。

实际上,我想知道maven-release-plugin如何处理模式1(尤其是本<parent>节,因为您在发行时不能拥有SNAPSHOT依赖项)。这听起来像是鸡肉或鸡蛋的问题,但我只是不记得它是否有效并且懒得测试它。


就我所见,它的扩展性非常好。svn:externals回答了我有关它麻烦的问题。
Jamie McCrindle 2010年

@jamie很高兴您发现它很有帮助。
Pascal Thivent 2010年

1
您能否详细说明如何使“ hack”工作?我已经完成了trunks项目,并期望您以“启动反应堆构建”为目标定位-pl选项,但这在结构上进行发布时会出现问题,因为该选项不会从根级别的构建传递过来我可以将其放置在release-Plugin的<arguments />选项中。因此释放:执行failes因为它试图工作,对根级POM ...

svn:externals hack是我很长时间以来见过的最有用的svn hack。对于在同一存储库中具有按项目分支的项目,这非常有帮助。
omerkudat 2012年

1
帕斯卡(Pascal),您好:如果模块部分中提到的项目不使用parent-pom作为其<parent>,而是使用some-other-project-parent-pom,您将如何处理版本号?对于此类项目的工件,我们将获得什么版本号(这些项目的<parent>部分中的工件的版本号或将这些项目作为模块列出的项目的版本号)?stackoverflow.com/questions/25918593/...
AKS

34

根据我的经验和Maven最佳实践,有两种“父poms”

  • “公司”父pom-此pom包含您公司的特定信息和配置,这些信息和配置继承每个pom,并且无需复制。这些信息是:

    • 仓库
    • 配送管理科
    • 常用插件配置(例如maven-compiler-plugin源和目标版本)
    • 组织,开发人员等

    准备此父pom时需要格外小心,因为您公司的所有pom都将继承该父pom,因此该pom必须成熟且稳定(发布父pom的版本不会影响发布您所有的公司项目!)

  • 第二种父pom是多模块父。我更喜欢您的第一个解决方案-这是多模块项目的默认Maven约定,通常代表VCS代码结构

目的是要可扩展到大规模构建,因此应可扩展到大量项目和工件。

Mutliprojects具有树木结构-因此您不必将其降低到父pom的一个级别。尝试找到适合您需求的项目结构-一个典型的例子是如何扰乱多模块项目

distibution/
documentation/
myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml
pom.xml

一些奖励问题:

  • 在哪里定义各种共享配置的最佳位置是哪里,如源代码控制,部署目录,通用插件等。(我假设是父级,但我经常对此感到bit恼,它们最终出现在每个项目中,而不是最终出现在每个项目中一个普通的)。

必须将此配置明智地分为“公司”父pom和项目父pom。与您所有项目有关的事情都归“公司”父级,而与当前项目有关的事情则归项目某人所有。

  • maven-release插件,hudson和nexus如何处理您如何设置多项目(可能是一个巨大的问题,当有人通过多项目构建的方式来抓捕时,问题就更大了)?

公司父pom必须先发布。对于多项目,适用标准规则。CI服务器需要了解所有内容才能正确构建项目。


1
因此,有两种类型的父项目/绒球。一个没有<modules>声明的。这是用于继承的代码。还有一个带有<multimodule>声明的父项目。这是子模块不继承的子模块,仅用于管理保持项目的构建。我对吗 ?
lisak 2011年

22
  1. 独立的父级是跨未耦合组件共享配置和选项的最佳实践。Apache有一个父pom项目,可以共享法律声明和一些常见的打包选项。

  2. 如果您的顶级项目中有实际工作,例如聚合javadoc或打包发行版,那么在完成该工作所需的设置与您要通过父项共享的设置之间将存在冲突。仅限父母的项目可以避免这种情况。

  3. 一种常见的模式(暂时忽略#1)是让带有代码的项目将父项目用作其父项,并使其将顶级项目用作父项。这使核心事物可以被所有人共享,但是避免了#2中描述的问题。

  4. 如果父结构与目录结构不同,则站点插件会非常困惑。如果您想构建一个汇总站点,则需要进行一些调整以解决此问题。

  5. Apache CXF是#2中的模式示例。


2
我看过ibilio,很多项目似乎更喜欢“独立”父pom。Hibernate,ActiveMQ,Jetty,XStream等。这表明它是事实上的机制。
Jamie McCrindle

2
独立父级的另一个缺点似乎是,Maven发布插件似乎希望在将父级发布之前将其固定到某个版本。大概没有什么大问题,因为父母不应该改变太多。
Jamie McCrindle

9

第三种方法有一个小问题。由于聚合POM(myproject / pom.xml)通常根本没有父级,因此它们不共享配置。这意味着所有这些聚合POM将仅具有默认存储库。

如果仅使用来自Central的插件,那不是问题,但是,如果您使用内部存储库中的plugin:goal格式运行插件,这将失败。例如,你可以foo-maven-plugin使用的的groupId org.example提供目标generate-foo。如果您尝试使用like之类的命令从项目根目录运行它mvn org.example:foo-maven-plugin:generate-foo,它将无法在聚合模块上运行(请参阅兼容性说明)。

几种解决方案是可能的:

  1. 将插件部署到Maven Central(并非总是可能的)。
  2. 在所有聚合POM中指定存储库部分(中断为DRY原则)。
  3. 在settings.xml中配置此内部存储库(在〜/ .m2 / settings.xml中的本地设置中,或在/conf/settings.xml中的全局设置中)。如果没有这些settings.xml,构建将会失败(对于大型内部项目而言,可以确定,这些内部项目永远都不应在公司外部构建)。
  4. 在聚合POM中使用带有存储库设置的父项(可能是太多的父项POM?)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.