Java Maven 父 pom 与模块 pom

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1992213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:11:41  来源:igfitidea点击:

Maven parent pom vs modules pom

javamaven-2build-process

提问by Jamie McCrindle

There seem to be several ways to structure parent poms in a multiproject build and I wondering if anyone had any thoughts on what the advantages / drawbacks are in each way.

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

The simplest method of having a parent pom would be putting it in the root of a project i.e.

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

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

where the pom.xml is both the parent project as well as describes the -core -api and -app modules

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

The next method is to separate out the parent into its own subdirectory as in

下一个方法是将父目录分离到它自己的子目录中,如

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

Where the parent pom still contains the modules but they're relative, e.g. ../myproject-core

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

Finally, there's the option where the module definition and the parent are separated as in

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

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

Where the parent pom contains any "shared" configuration (dependencyManagement, properties etc.) and the myproject/pom.xml contains the list of modules.

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

The intention is to be scalable to a large scale build so should be scalable to a large number of projects and artifacts.

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

A few bonus questions:

一些奖金问题:

  • Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).
  • How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?
  • 在源代码控制、部署目录、通用插件等中定义各种共享配置的最佳位置在哪里。一个常见的)。
  • maven-release 插件、hudson 和 nexus 如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人被多项目构建的设置方式所吸引,那就更重要了)?

Edit: Each of the sub projects have their own pom.xml, I've left it out to keep it terse.

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

采纳答案by Pascal Thivent

In my opinion, to answer this question, you need to think in terms of project life cycle and version control. In other words, does the parent pom have its own life cycle i.e. can it be released separately of the other modules or not?

在我看来,要回答这个问题,需要从项目生命周期和版本控制两个方面来思考。换句话说,父 pom 是否有自己的生命周期,即它是否可以与其他模块分开发布?

If the answer is yes(and this is the case of most projects that have been mentioned in the question or in comments), then the parent pom needs his own module from a VCS and from a Maven point of view and you'll end up with something like this at the VCS level:

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

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

This makes the checkout a bit painful and a common way to deal with that is to use svn:externals. For example, add a trunksdirectory:

这使得结帐有点痛苦,处理这种情况的常用方法是使用svn:externals. 例如添加一个trunks目录:

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

With the following externals definition:

使用以下外部定义:

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

A checkout of trunkswould then result in the following local structure (pattern #2):

然后结帐trunks将导致以下本地结构(模式#2):

root/
  parent-pom/
    pom.xml
  projectA/

Optionally, you can even add a pom.xmlin the trunksdirectory:

或者,您甚至可以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

This pom.xmlis a kind of "fake" pom: it is never released, it doesn't contain a real version since this file is never released, it only contains a list of modules. With this file, a checkout would result in this structure (pattern #3):

pom.xml是一种“假”pom:它从未发布过,它不包含真实版本,因为此文件从未发布过,它只包含一个模块列表。使用此文件,结帐将导致此结构(模式 #3):

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

This "hack" allows to launch of a reactor build from the root after a checkout and make things even more handy. Actually, this is how I like to setup maven projects and a VCS repository for large builds: it just works, it scales well, it gives all the flexibility you may need.

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

If the answer is no(back to the initial question), then I think you can live with pattern #1 (do the simplest thing that could possibly work).

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

Now, about the bonus questions:

现在,关于奖金问题:

  • Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).
  • 在源代码控制、部署目录、通用插件等中定义各种共享配置的最佳位置在哪里。一个常见的)。

Honestly, I don't know how to not give a general answer here (like "use the level at which you think it makes sense to mutualize things"). And anyway, child poms can always override inherited settings.

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

  • How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?
  • maven-release 插件、hudson 和 nexus 如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人被多项目构建的设置方式所吸引,那就更重要了)?

The setup I use works well, nothing particular to mention.

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

Actually, I wonder how the maven-release-plugin deals with pattern #1 (especially with the <parent>section since you can't have SNAPSHOT dependencies at release time). This sounds like a chicken or egg problem but I just can't remember if it works and was too lazy to test it.

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

回答by bmargulies

  1. An independent parent is the best practice for sharing configuration and options across otherwise uncoupled components. Apache has a parent pom project to share legal notices and some common packaging options.

  2. If your top-level project has real work in it, such as aggregating javadoc or packaging a release, then you will have conflicts between the settings needed to do that work and the settings you want to share out via parent. A parent-only project avoids that.

  3. A common pattern (ignoring #1 for the moment) is have the projects-with-code use a parent project as their parent, and have it use the top-level as a parent. This allows core things to be shared by all, but avoids the problem described in #2.

  4. The site plugin will get very confused if the parent structure is not the same as the directory structure. If you want to build an aggregate site, you'll need to do some fiddling to get around this.

  5. Apache CXFis an example the pattern in #2.

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

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

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

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

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

回答by cetnar

From my experience and Maven best practices there are two kinds of "parent poms"

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

  • "company" parent pom - this pom contains your company specific information and configuration that inherit every pom and doesn't need to be copied. These informations are:

    • repositories
    • distribution managment sections
    • common plugins configurations (like maven-compiler-plugin source and target versions)
    • organization, developers, etc

    Preparing this parent pom need to be done with caution, because all your company poms will inherit from it, so this pom have to be mature and stable (releasing a version of parent pom should not affect to release all your company projects!)

  • second kind of parent pom is a multimodule parent. I prefer your first solution - this is a default maven convention for multi module projects, very often represents VCS code structure
  • “公司”父 pom - 此 pom 包含您公司的特定信息和配置,这些信息和配置继承了每个 pom,不需要复制。这些信息是:

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

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

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

The intention is to be scalable to a large scale build so should be scalable to a large number of projects and artifacts.

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

Mutliprojects have structure of trees - so you aren't arrown down to one level of parent pom. Try to find a suitable project struture for your needs - a classic exmample is how to disrtibute mutimodule projects

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

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

A few bonus questions:

  • Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).

一些奖金问题:

  • 在源代码控制、部署目录、通用插件等中定义各种共享配置的最佳位置在哪里。一个常见的)。

This configuration has to be wisely splitted into a "company" parent pom and project parent pom(s). Things related to all you project go to "company" parent and this related to current project go to project one's.

此配置必须明智地分为“公司”父 pom 和项目父 pom(s)。与您所有项目相关的事情转到“公司”父级,而与当前项目相关的事情转到自己的项目。

  • How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?
  • maven-release 插件、hudson 和 nexus 如何处理你如何设置你的多项目(可能是一个巨大的问题,如果有人被多项目构建的设置方式所吸引,那就更重要了)?

Company parent pom have to be released first. For multiprojects standard rules applies. CI server need to know all to build the project correctly.

公司父 pom 必须首先被释放。对于多项目标准规则适用。CI 服务器需要知道所有才能正确构建项目。

回答by Ivan Dubrov

There is one little catch with the third approach. Since aggregate POMs (myproject/pom.xml) usually don't have parent at all, they do not share configuration. That means all those aggregate POMs will have only default repositories.

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

That is not a problem if you only use plugins from Central, however, this will fail if you run plugin using the plugin:goal format from your internal repository. For example, you can have foo-maven-pluginwith the groupId of org.exampleproviding goal generate-foo. If you try to run it from the project root using command like mvn org.example:foo-maven-plugin:generate-foo, it will fail to run on the aggregate modules (see compatibility note).

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

Several solutions are possible:

有几种可能的解决方案:

  1. Deploy plugin to the Maven Central (not always possible).
  2. Specify repository section in all of your aggregate POMs (breaks DRYprinciple).
  3. Have this internal repository configured in the settings.xml (either in local settings at ~/.m2/settings.xml or in the global settings at /conf/settings.xml). Will make build fail without those settings.xml (could be OK for large in-house projects that are never supposed to be built outside of the company).
  4. Use the parent with repositories settings in your aggregate POMs (could be too many parent POMs?).
  1. 将插件部署到 Maven Central(并非总是可行)。
  2. 在所有聚合 POM 中指定存储库部分(违反DRY原则)。
  3. 在 settings.xml 中配置此内部存储库(在 ~/.m2/settings.xml 中的本地设置中或 /conf/settings.xml 中的全局设置中)。没有那些 settings.xml 会使构建失败(对于永远不应该在公司外部构建的大型内部项目可能没问题)。
  4. 在聚合 POM 中使用具有存储库设置的父级(可能是太多父级 POM?)。