Maven父母pom vs模块pom

时间:2010-01-02 17:38:37

标签: java maven-2 build-process

在多项目构建中似乎有几种方法来构建父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的核

最后,有一个选项,模块定义和父项分开,如

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

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

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

一些奖励问题:

  • 在源控件,部署目录,常见插件等中定义各种共享配置的最佳位置在哪里(我假设是父级,但我经常被这种情况所困扰,而且他们最终都是项目而不是常见项目。)
  • maven-release插件,hudson和nexus如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人因为如何设置多项目构建而被抓住了,那就更多了)?

编辑:每个子项目都有自己的pom.xml,我把它留了下来以保持简洁。

4 个答案:

答案 0 :(得分:163)

在我看来,要回答这个问题,你需要考虑项目生命周期和版本控制。换句话说,父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.xml目录中添加trunks

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

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

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

现在,关于奖金问题:

  
      
  • 在源控件,部署目录,常见插件等中定义各种共享配置的最佳位置在哪里(我假设是父级,但我经常被这种情况所困扰,而且他们最终都是项目而不是常见项目。)
  •   

老实说,我不知道如何在这里不给出一般性的答案(比如“使用你认为让事情互相合理的水平”)。无论如何,子poms总是可以覆盖继承的设置。

  
      
  • maven-release插件,hudson和nexus如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人因为如何设置多项目构建而被抓住了,那就更多了)?
  •   

我使用的设置效果很好,没有什么特别值得一提的。

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

答案 1 :(得分:33)

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

  • “company”parent pom - 此pom包含您公司特定的信息和配置,它们继承每个pom而不需要复制。这些信息是:

    • 存储库
    • 分发管理部分
    • 常见的插件配置(如maven-compiler-plugin源和目标版本)
    • 组织,开发人员等

    准备这个父pom需要谨慎,因为你所有公司的poms都将继承它,所以这个pom必须成熟稳定(发布一个父pom版本不应该影响你发布所有的公司项目! )

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

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

Mutliprojects具有树木的结构 - 因此您不会向下生成一级父母pom。尝试为您的需求找到合适的项目结构 - 一个典型的例子是如何分解mutimodule项目

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

一些奖励问题:

     
      
  • 在源控件,部署目录,常见插件等中定义各种共享配置的最佳位置在哪里(我假设是父级,但我经常被这种情况所困扰,而且他们最终都是项目,而不是一个共同的)。
  •   

此配置必须明智地拆分为“公司”父pom和项目父pom。与你所有项目相关的事情都转到“公司”的父母,这与当前项目有关,转到项目一。

  
      
  • maven-release插件,hudson和nexus如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人因为如何设置多项目构建而被抓住了,那就更多了)?
  •   

必须首先发布公司父母pom。对于多项目,适用标准规则。 CI服务器需要知道所有正确构建项目。

答案 2 :(得分:22)

  1. 独立父级是在其他非耦合组件之间共享配置和选项的最佳实践。 Apache有一个父pom项目来分享法律声明和一些常见的包装选项。

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

  3. 一个常见的模式(暂时忽略#1)是让代码项目使用父项目作为父项目,并让它使用顶级作为父项目。这允许所有人共享核心内容,但避免了#2中描述的问题。

  4. 如果父结构与目录结构不同,则网站插件会变得非常混乱。如果你想建立一个聚合网站,你需要做一些摆弄来解决这个问题。

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

答案 3 :(得分:9)

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

如果您只使用Central的插件,那不是问题,但是,如果您使用内部存储库中的插件:目标格式运行插件,则会失败。例如,您可以foo-maven-plugin使用{I} {c}}提供目标org.example。如果您尝试使用generate-foo之类的命令从项目根目录运行它,它将无法在聚合模块上运行(请参阅compatibility note)。

可能有几种解决方案:

  1. 将插件部署到Maven Central(并非总是可行)。
  2. 在所有聚合POM中指定存储库部分(中断DRY原则)。
  3. 在settings.xml中配置此内部存储库(在〜/ .m2 / settings.xml的本地设置中或在/conf/settings.xml的全局设置中)。如果没有那些settings.xml,那么构建就会失败(对于那些永远不应该在公司外部构建的大型内部项目来说可能没问题。)
  4. 在聚合POM中使用带有存储库设置的父级(可能是太多的父POM?)。