Maven父pom vs模块pom

在多项目构建中,似乎有几种方法来构建父poms,我想知道是否有人对每种方法的优点/缺点有任何想法。

拥有一个父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包含任何“共享”配置(依赖管理,属性等),myproject/pom.xml包含模块列表。

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

一些额外的问题:

  • 哪里是定义各种共享配置的最佳位置,比如在源代码控制、部署目录、公共插件等(我假设是父目录,但我经常被这个问题所咬,它们最终在每个项目中而不是一个公共项目中)。
  • maven-release插件,hudson和nexus如何处理你如何设置你的多项目(这可能是一个大问题,如果有人被多项目构建是如何设置的搞清楚了,问题就更大了)?

编辑:每个子项目都有自己的pom.xml,为了简洁起见,我省略了它。

160211 次浏览
  1. 独立的父组件是跨其他未耦合组件共享配置和选项的最佳实践。Apache有一个父pom项目来共享法律通知和一些常见的打包选项。

  2. 如果您的顶级项目中有实际的工作,比如聚合javadoc或打包一个版本,那么在完成该工作所需的设置和希望通过父级共享的设置之间就会出现冲突。只有父元素的项目可以避免这种情况。

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

  4. 如果父结构与目录结构不相同,站点插件将会非常混乱。如果您希望构建一个聚合站点,则需要做一些处理来解决这个问题。

  5. Apache CXF是#2中的模式的一个例子。

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

  • "company" parent pom -这个pom包含你的公司特定的信息和配置,继承每个pom,不需要复制。这些信息是:

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

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

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

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

multiliprojects有树的结构-所以你不会被箭头指向父pom的一层。尝试为您的需求找到一个合适的项目结构——一个经典的例子是如何分发多模块项目

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

一些额外的问题:

  • 哪里是定义各种共享配置的最佳位置,比如在源代码控制、部署目录、公共插件等(我假设是父目录,但我经常被这个问题所咬,它们最终在每个项目中而不是一个公共项目中)。

这个配置必须明智地分成“公司”父pom和项目父pom。与你所有项目相关的东西归“公司”母公司,与当前项目相关的归项目一。

  • maven-release插件,hudson和nexus如何处理你如何设置你的多项目(这可能是一个大问题,如果有人被多项目构建是如何设置的搞清楚了,问题就更大了)?

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

在我看来,要回答这个问题,您需要从项目生命周期和版本控制的角度来考虑。换句话说,父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/

你甚至可以选择在trunks目录中添加pom.xml:

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>部分,因为在发布时你不能有快照依赖项)。这听起来像是一个先有鸡还是先有蛋的问题,但我就是不记得它是否有效,也懒得测试它。

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

如果你只使用来自Central的插件,这不是问题,但是,如果你从内部存储库中使用plugin:goal格式运行插件,这将会失败。例如,你可以有foo-maven-pluginorg.example的groupId,提供目标generate-foo。如果你试图使用mvn org.example:foo-maven-plugin:generate-foo这样的命令从项目根运行它,它将无法在聚合模块上运行(参见兼容性注意)。

有几种解决方案:

  1. 将插件部署到Maven中心(并不总是可能的)。
  2. 在所有聚合POMs中指定存储库部分(违反原则)。
  3. 在settings.xml中配置这个内部存储库(在~/.m2/settings.xml的本地设置中或在/conf/settings.xml的全局设置中)。如果没有这些settings.xml,将导致构建失败(对于从来不会在公司外部构建的大型内部项目可能没问题)。
  4. 在聚合POMs中使用父级存储库设置(可能有太多的父级POMs?)