首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Maven的pom打包:父POM、聚合POM与BOM如何分工
📅 2026/11/3 18:25:25
✍️ 爱科研究院
👁 阅读 3,247
一个根POM写了modules能一次构建两个模块这两个模块就会继承它的配置吗不会。被一起构建与继承同一份配置是两种不同关系。下面把它们刻意拆开assembly负责聚合config-parent负责提供配置。实跑结果是child进入了assembly这次构建却只继承config-parent的属性另一个同样参与构建的plain没有继承两者的自定义属性。三个POM都可以写packagingpom但这一行本身没有建立任何父子、聚合或BOM导入关系。要判断一个POM在做什么应继续看谁通过parent引用它、它是否声明modules以及它是否被当作BOM导入。2026-11-02修订加入继承与聚合分离的最小实验修正relativePath默认行为并补全BOM示例。先把继承和聚合拆开运行建立下面的目录结构。四个POM都只用于配置实验不包含Java源码pom-roles/ ├─ config-parent/pom.xml ├─ child/pom.xml ├─ plain/pom.xml └─ assembly/pom.xmlconfig-parent/pom.xml定义一个共享属性不声明任何模块project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdexample.roles/groupId artifactIdconfig-parent/artifactId version1.0/version packagingpom/packaging properties shared.settingfrom-parent/shared.setting /properties /projectchild/pom.xml通过parent建立继承关系。这里没有再写groupId和version它们来自父POMproject xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion parent groupIdexample.roles/groupId artifactIdconfig-parent/artifactId version1.0/version relativePath../config-parent/pom.xml/relativePath /parent artifactIdchild/artifactId packagingpom/packaging /projectplain/pom.xml保持独立不声明这个父POMproject xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdexample.roles/groupId artifactIdplain/artifactId version1.0/version packagingpom/packaging /project最后由assembly/pom.xml聚合这两个模块。故意再放一个属性观察它是否会传下去project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdexample.roles/groupId artifactIdassembly/artifactId version1.0/version packagingpom/packaging properties aggregator.flagfrom-assembly/aggregator.flag /properties modules module../plain/module module../child/module /modules /project在pom-roles目录运行mvn -B -ntp -f assembly/pom.xml validate本次使用Maven 3.9.12、JDK 21.0.2Reactor输出为Reactor Build Order: plain [pom] child [pom] assembly [pom]三个项目的validate都成功。config-parent虽然被读取来构造child的模型却没有因此成为本次Reactor构建的一个项目它没有被assembly的modules列出。读取父模型不等于执行父项目的生命周期。再分别生成两个模块的有效POM$childEffective Join-Path $PWD effective-child.xml $plainEffective Join-Path $PWD effective-plain.xml mvn -B -ntp -f child/pom.xml org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -Doutput$childEffective mvn -B -ntp -f plain/pom.xml org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -Doutput$plainEffective本次读取结果如下项目参与assembly的构建shared.settingaggregator.flagchild是from-parent没有plain是没有没有child拿到了真正父POM的属性两者都没有因为被聚合就继承assembly的属性。这是拆分角色以后最直接的证据与官方POM Reference对继承和聚合的区分一致。这里验证的是模型和validate阶段没有编译、测试或打包应用。图1实线表示配置继承虚线和范围框表示聚合。本次Reactor顺序是plain、child、assemblyconfig-parent只提供父模型。parent决定配置从哪里来modules决定这次构建收集谁父POM适合集中提供需要继承的配置例如properties、dependencyManagement以及插件管理。它通过子项目的parent生效不要求父POM同时列出这个子项目。一个项目只有一个直接父POM但父POM本身还可以有自己的父POM形成继承链。父POM中的普通dependencies也会被继承所以公共依赖只需要统一版本、并不希望每个模块都使用时应放进dependencyManagement再由需要的模块声明依赖。artifactId不会从父POM继承否则不同子项目就无法保持各自身份。聚合POM的modules则给Reactor提供本次构建的项目入口。Maven收集模块并依据实际项目关系排序不是简单执行一张不分析依赖的目录清单。依赖管理里只写了一项也不会因此改变Reactor排序真正使用的项目依赖等关系才参与这项判断。Maven多模块指南列出了排序依据。项目规模小时让同一份根POM兼任父POM和聚合POM通常更直观。需要复用统一父配置、又希望不同产品按各自模块集合构建时可以像实验这样拆开。选择拆分的理由应来自配置复用和构建边界而不是为了给每个角色再建一个目录。relativePath不写和写空不是一回事这两个写法需要单独区分!-- parent中不写relativePath默认值是../pom.xml -- !-- parent中显式写空关闭通过本地相对路径查找父POM -- relativePath/在常见的本地开发查找路径中Maven先检查这个相对位置的父POM再查本地仓库和远程仓库候选文件的groupId、artifactId、version也必须匹配。不能把默认行为说成“没写relativePath就直接从仓库找”。Maven 3.9.12模型参考给出了默认值与空字符串含义。本次另外建了一个default-parent/child目录把匹配的父POM放在default-parent/pom.xml并保证它没有安装进实验仓库。不写relativePath子项目仍成功继承了父属性同样位置的另一子项目改成relativePath/在离线仓库里就以Non-resolvable parent POM失败。图2写空relativePath会关闭相对路径搜索。本次失败还依赖离线且父POM未安装父POM能从仓库解析时写空仍可成功。这个反例验证的是本地相对路径搜索被关闭。若父POM已经能从仓库解析写空仍可能成功不能把这次的失败推广为“relativePath写空不能使用父POM”。还有一个不同的失败把被继承父POM的packaging设为jar模型校验会拒绝。本次错误中的关键部分是Invalid packaging for parent POM ... must be pom but is jarBOM提供依赖管理不提供另一份完整父配置父POM和聚合POM都使用pom打包常用BOM也如此但BOM的使用关系是消费者在dependencyManagement中导入它。再创建roles-bom/pom.xmlproject xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdexample.roles/groupId artifactIdroles-bom/artifactId version1.0/version packagingpom/packaging properties bom.markernot-inherited/bom.marker /properties dependencyManagement dependencies dependency groupIdexample.roles/groupId artifactIddemo-lib/artifactId version7.0/version /dependency /dependencies /dependencyManagement /project消费者bom-consumer/pom.xml不继承它只导入管理项project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdexample.roles/groupId artifactIdbom-consumer/artifactId version1.0/version packagingpom/packaging dependencyManagement dependencies dependency groupIdexample.roles/groupId artifactIdroles-bom/artifactId version1.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdexample.roles/groupId artifactIddemo-lib/artifactId /dependency /dependencies /project把自建BOM安装到单独的示例仓库然后检查消费者模型$roleRepository Join-Path $PWD .role-repository $bomEffective Join-Path $PWD effective-bom-consumer.xml mvn -B -ntp -Dmaven.repo.local$roleRepository -f roles-bom/pom.xml org.apache.maven.plugins:maven-install-plugin:3.1.3:install mvn -B -ntp -Dmaven.repo.local$roleRepository -f bom-consumer/pom.xml org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -Doutput$bomEffective本次有效POM中消费者的demo-lib版本成为7.0但没有继承bom.marker属性。这里仍只检查模型没有解析这个人工示例库的JAR。一个项目可以保留原来的直接父POM同时导入BOM导入也不会把目标POM的modules变成本次要构建的模块。BOM便于集中维护版本但它不是Maven自动授予的兼容性认证。版本组合是否经过测试、覆盖哪些场景需要看发布者的说明并由自己的应用测试验证。更细的覆盖与导入边界可接着看dependencies、dependencyManagement与BOM的有效POM对照。pom打包本身承诺了什么pom打包的默认生命周期没有Java编译和JAR打包绑定但可以把POM安装到本地仓库、发布到远程仓库。上面的本地安装已经留下了一个可被消费者解析的POM构件。它不生成可运行JAR不等于它“没有构件”或“不能发布”。默认绑定可查Maven Core的pom生命周期表。同样默认没有编译动作也不是禁止目录中存在源码或禁止项目显式绑定其他插件执行。分析具体构建时需要继续看build和激活的profiles。回到最初的问题最有用的判断顺序是先看packaging决定的默认构建方式再沿parent、modules和import分别追关系。它们可以集中在同一份POM里也可以按需要拆开是否共享同一份文件不改变三种机制各自的边界。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/11/3 18:25:25
te_PP-OCRv5_mobile_rec_onnx ONNX格式优势:跨平台部署完全指南
2026/11/3 18:25:25
【Go语言基础【5】】运算符基础
2026/11/3 18:25:25
【Go语言基础【3】】变量、常量、值类型与引用类型
2026/11/3 19:25:57
深度 | DeepSeek 把生产推理引擎开源了:同一个代码库,英伟达与昇腾并列支持
2026/11/3 19:25:57
外贸客户不回复怎么办?一套不催单的跟进方法
2026/11/3 19:25:57
2026年AI岗位新地图:小白也能找到高薪入口,速看!
2026/11/3 19:25:57
JAVA25+Spring Boot 4.1.0 +Spring AI 2.0.1 调用DeepSeek模型之底层http日志输出
2026/11/3 19:25:57
【Linux操作系统】进程篇(六):进程上下文切换与 O(1) 调度算法
2026/11/3 19:20:51
面向攻击者能力演变的基于强化学习与行为树的自适应网络防御
2026/11/3 0:03:28
淘宝商品详情API开发实战与性能优化指南
2026/11/3 0:03:28
Unity Package Manager刷新错误排查与解决方案
2026/11/3 0:03:28
Java record 规范构造器能否被反序列化或反射绕过
2026/11/3 4:05:41
面向复杂光照与角度的宠物面部识别鲁棒性增强策略
2026/11/3 4:05:35
DRV8818PWPR与R7FA8M1AHECBD工业步进驱动实战指南
2026/11/3 4:05:30
STM32与DRV8818双极步进电机驱动方案:从选型到调试全流程解析
2026/11/3 4:05:41
面向复杂光照与角度的宠物面部识别鲁棒性增强策略
2026/11/3 4:05:35
DRV8818PWPR与R7FA8M1AHECBD工业步进驱动实战指南
2026/11/3 4:05:30
STM32与DRV8818双极步进电机驱动方案:从选型到调试全流程解析