分层多模块项目的 Maven 命名约定
Posted
技术标签:
【中文标题】分层多模块项目的 Maven 命名约定【英文标题】:Maven naming conventions for hierarchical multiple module projects 【发布时间】:2012-03-15 04:20:54 【问题描述】:我有一个关于具有分层目录结构的多模块项目中的 Maven 命名约定(groupId、artifactId 和目录名称)的问题。
研究
在问之前,我浏览了其他关于这个主题的网络以及我为自己清除的内容:
Possible duplication for my question, but it does not cover multiple-hierarchy levels.
Project directory name should match artificatId.
Guide to Naming Conventions 举个例子:
groupId 将在所有项目中唯一标识您的项目,因此我们需要强制实施命名架构。它必须遵循包名规则(例如 org.apache.maven、org.apache.commons、org.apache.maven.plugins)
artifactId 如果您创建了它,那么您可以选择任何您想要的名称,使用小写字母且没有奇怪的符号。 (例如 maven、commons-math)
这很简单,我理解它,但仍有一些不清楚的地方。
约定中提到的artifactId 示例只能应用于一级层次结构模块。
示例
我浏览了 maven 存储库并提取了一些示例:
Spring 主要使用名称:spring-core、spring-context、spring-context-support。所有独立模块都是一级层次结构和 spring- 前缀以提高搜索效率。没有问题,因为层次结构没有那么深。
Apache CXF 命名对于 Apache 来说是非常规的。工件是独立的模块,名称中最多有 5 个可能的不同工件,例如。 cxf-tools-wsdlto-databinding-jaxb。
有很多工件(cxf-rt-databinding-jaxb、cxf-rt-databinding-aegis、cxf-rt-databinding-xmlbeans、cxf-rt-databinding-sdo)可以分组到多个模块项目中( cxf-rt-databindings),但他们没有,所以名字变成了意大利面条。
最后,Maven Plugins 首先是一个多模块项目(在 org.apache.maven 之后),其中包含以下工件:maven-compiler-plugin、maven-enforcer-plugin。
有很多示例,并且都遵循不同的约定关于命名 artifactIds(因此是项目目录)。
结果
从示例中获取最佳实践让我们回顾层级。
一层层级命名将是 (
groupId: org.organization.project
artifactId: project-portal ---.
|
project-portal-service
|
project-portal-plugins (continued on next diagram)
|
project-portal-util
(续)两级层次结构是:
groupId: org.organization.project.plugins
artifactId: project-portal-plugins ---.
|
project-sample-plugin
|
project-another-great-plugin
|
???? (multiple module project)
你看到问号了吗?这就是
问题
我遵循示例中的约定(忽略意大利面条 Apache CXF 示例):
根 - 项目门户(例如 spring-core、maven-core) 一级层次结构名称从根继承 - project-portal-plugins(例如 spring-context-support)。 二级层次结构名称 - project-sample-plugin(例如 maven-compiler-plugin)。现在我们被困在第三级,就像在没有保存和检查点的旧游戏中一样。
-
这是从 Maven 示例中获取的用于更深层次结构级别的正确目录命名路径吗?
您是否遵循任何约定或规则来支持简单的目录和工件名称,避免在更深层次上使用意大利面条名称?
如果存在简单名称,groupId 是否会在存储库中保存重复的工件名称(由于简单性会发生这种情况)?
如何在网络/存储库中搜索和查找名称重复的工件(因为简单)?
我不想在我的项目结构中看到像 project-portal-liferay-plugins-themes 之类的模块用于父级或更糟糕的 project-portal-liferay-plugins-themes-white-puppy-wtf-name 用于孩子.
如果您可以针对任何提到的问题和可能的问题提供您的意见和实践,那不仅对我有很大帮助,而且对使用 maven 的每个人也有很大帮助。谢谢。
【问题讨论】:
【参考方案1】:我认为没有明确规定在这种情况下应如何设置项目结构的约定。
例如我会尝试回答工件的名称最终在哪里以及发生冲突的可能性是什么。 对于像 spring 这样的框架,将项目名称放在 artifactId(“spring-*”)中确实有意义,对于 commons-library 也是如此(尽管“commons-logging”可能是一个有风险的名称)。
对于独立运行的项目,我可能没有必要这样做。但看起来您将使用一个 liferay 门户,其中会有很多不同的罐子,所以我鼓励为工件添加前缀。 但我不会尝试根据 artifactId 重建项目结构。所以“project-modulename”将是一个好的模块名称。由于 jar 将构建类路径,并且在构建过程中定义了依赖结构,因此这不是问题。如果您需要根据 jars 列表重建依赖树:maven 在 META-INF 中包含信息(如果您使用我也推荐的 release-plugin),因此可以从那里检索信息。
我还建议不要将模块嵌套得太深。 Eclipse 对此有一些问题(IntelliJ 没有,Netbeans afaik 也支持嵌套结构)。
与插件模块相比,主门户模块可能不会经常发生变化。所以我把它们分成单独的项目是有意义的——这也允许单独发布项目。
对我来说,使用“-parent”后缀命名父模块是一个好习惯。这些模块很少用作依赖项,依赖项的“-parent”表示存在可疑之处。正如您所说: artifacId 和模块名称应该相同。我还建议在 pom.xml 中使用 artifactId 作为名称。一些插件在这里没有考虑差异,如果这些值都相同,Eclipse 的表现会更好。
确实,goupId 和 artifactId 经常包含重复信息(例如,其中的一部分将是项目名称)。如果这是故意的,或者是在过去几年发生的……?我不知道,但我会保持这种方式。使用 GAV(P) 坐标(groupId、artifactId、version、(packaging))来识别工件。如果 groupId 或 artifactId 包含 projectname 工件,如果您只有其中一个,则更容易找到。
如果您正在运行存储库管理器(如 Nexus、Artifactory、Archiva),则查找工件很容易。搜索通常会呈现 groupId/artifactId 等,因此搜索“util”将为您提供足够的信息来找到您正在寻找的工件。
希望这会有所帮助 :) 问候
我们
【讨论】:
所以你基本上是这么说的,以khmarbaise为例,你会选择artifactId
s appname-module1
,appname-module2
,appname-chhild1
,appname-subchild-1
等等。因为这会导致例如appname-module1.jar
而不是 module1.jar
,而后者与另一个 JAR 冲突的可能性要大得多,这个 JAR 可能存在于其他依赖于 appname
模块的项目中,对吧?例如,您宁愿生成appname-client.jar
和appname-server.jar
而不是client.jar
和server.jar
。
是的。因为通常所有的罐子最终都在某个地方的 lib 文件夹中。如果两个共享名称,您将要搜索很久。 Maven 还添加了一个版本,因此冲突可能非常罕见。但是为什么要冒险......对于超级罐子,问题不是太大。但是 spring boot 集成了 jar 文件,而不是创建一个解压的 uber jar。所以风险还是存在的。我还会检查 maven 在 maven 存储库中的作用,因此在那里创建的目录结构与您的模块相匹配 - 只是为了让事情井井有条。【参考方案2】:
在早期使用 maven 时,我遵循您描述的以下结构:
appname
+--- appname-module1
+--- appname-module2
+--- appname-module2-chhild1
+--- appname-module2-chhild2
+--- appname-module3
但是,如果您获得更多关卡,这将变得可笑。
所以我决定改变主意,现在使用以下方法:
appname
+--- module1
+--- module2
+--- chhild1
+--- subchild1
+--- chhild2
+--- module3
我在关卡中唯一改变的是 groupId...
appname (groupId: com.soebes.appname)
+--- module1 (groupId: com.soebes.appname.module1)
+--- module2 (groupId: com.soebes.appname.module2)
+--- chhild1 (groupId: com.soebes.appname.module1.child1)
+--- chhild2 (groupId: com.soebes.appname.module1.child2)
+--- module3 (groupId: com.soebes.appname.module3)
【讨论】:
达到一定程度就很可笑了,确实如此,但是在一个模块数量相当多的项目中(我有一个超过50个的,例如,我喜欢保留groupId:artifactId
,文件夹结构和项目<name>
同步,这样当我构建反应器时,我可以清楚地看到正在构建的内容并保留层次结构的视图(因为反应器不一定按顺序构建)。另一件事是对于大型项目,您可能有多个子项目,它们可能具有相同的 artifactId(但 groupId 不同,这有助于避免混淆 - 成本明显:))
我正在将 jenkins 用于具有 150 个模块的项目,并且基于模块结构(由 jenkins 打印出来),我可以毫无问题地找到正确的位置。【参考方案3】:
另一种可能的方法是查看功能组而不是层次结构。
假设项目 B 有 webapps、插件和核心库,那么所有模块共享相同的 group id (com.mycompany.b) 并且 artefacts 分别命名为 webapp-???、plugin-???和核心-???。
我们还使用前面提到的 -parent 约定:因此,所有 webapps 的父 POM 称为 webapp-parent.pom。
【讨论】:
以上是关于分层多模块项目的 Maven 命名约定的主要内容,如果未能解决你的问题,请参考以下文章