《Maven <packaging>pom</packaging>深度解析:父POM、聚合POM与BOM的三重身份》

kayokoi 发布于 2025-07-28 48 次阅读


在前面的文章中,我们已经接触到Maven的POM文件和依赖管理。当谈及<packaging>元素时,除了常见的jarwarpom类型扮演着至关重要的角色。一个声明了<packaging>pom</packaging>的Maven项目,其本身通常不包含需要编译的Java源代码,也不会产出可执行或可部署的构件。它的核心价值在于其“管理”和“声明”的职责。本文将深度剖析<packaging>pom</packaging>项目所能扮演的三重身份:父POM、聚合POM与BOM。

身份一:父POM (Parent POM) - “家族族长,制定家规”

核心职责:为子模块提供一个可继承的配置基线,以实现配置共享、版本统一和规范管理,从而减少子模块中的重复配置。

pom.xml 中的体现

  • 子模块中:通过 <parent> 标签声明对父POM的引用。

    XML

    <project ...>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>my-parent-project</artifactId>
            <version>1.0.0</version>
            <relativePath>../my-parent-project/pom.xml</relativePath> </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>a-module</artifactId> ...
    </project>
    

    子工程配置继承关系后,其坐标中的 <groupId><version> 若未显式定义,则会自动继承父工程的。<relativePath> 指定父工程pom文件的相对位置;若不指定,Maven会先从本地仓库查找,再从远程仓库查找。

  • 父POM本身 (my-parent-project/pom.xml):

    • 必须声明 <packaging>pom</packaging>
    • 通常会定义:
      • <properties>:共享属性,如统一的JDK版本、依赖版本号。
      • <dependencyManagement>:集中管理依赖版本(子模块仍需显式声明依赖,但可省略版本)。
      • <pluginManagement>:集中管理插件版本和默认配置(子模块仍需显式声明插件,但可省略版本和部分配置)。
      • <repositories><pluginRepositories>:统一仓库配置。
      • <distributionManagement>:统一部署配置。

工作机制:子模块通过 <parent> 标签“认领”父POM后,就会自动继承父POM中定义的上述可继承元素。子模块也可以覆盖继承来的配置。

类比:“家族族长”制定了“家规”(如采购标准 - <dependencyManagement>;装修风格 - <pluginManagement>)和共享资源(公共基金 - <properties>)。家庭成员(子模块)自动遵守并可使用这些规范和资源。

身份二:聚合POM (Aggregator POM) - “项目总指挥,集合队伍统一行动”

核心职责:将多个独立的子模块组织起来,以便能够一次性地对所有这些模块执行构建命令(如 mvn clean install)。它主要用于简化多模块项目的构建管理,实现项目的“一键构建”。

pom.xml 中的体现

  • 聚合POM本身
    • 必须声明 <packaging>pom</packaging>
    • 最关键的元素是 <modules> 标签,它列出了所有被聚合的子模块的目录名称(相对于聚合POM的路径)。 
    <project ...>
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>an-aggregator</artifactId>
        <version>1.0.0</version>
        <packaging>pom</packaging>
    
        <modules>
            <module>module-one</module>      <module>module-two</module>      <module>../another-module</module> </modules>
        ...
    </project>
    

工作机制:当你在聚合POM的目录下执行Maven命令时,Maven的**反应堆 (Reactor)**机制会启动。它会解析聚合POM,找到 <modules> 中列出的所有模块,分析模块间的依赖关系,并按照正确的顺序(先构建被依赖的模块,后构建依赖它的模块)依次构建所有模块。

类比:“项目总指挥”手握所有“施工队”(子模块)名单,一声令下,各施工队按既定工序协同作业完成整个工程。

父POM与聚合POM的关系: 一个聚合POM通常也是其所聚合模块的父POM。这是非常常见且推荐的做法(例如,yudao-cloud 的根POM就是如此,它既是所有模块的父,也聚合了所有模块)。但理论上,父子关系和聚合关系是可以分离的。一个项目可以有一个父POM,同时被另一个不同的聚合POM所管理。

身份三:BOM (Bill of Materials) - “权威的依赖版本推荐清单”

核心职责:提供一个集中管理的、经过测试和验证的、相互兼容的依赖版本集合。它本身不添加任何依赖到项目中,也不直接参与项目的构建流程(除非被其他POM引用其<dependencyManagement>)。它的主要目的是被其他项目“导入”其 <dependencyManagement> 部分,从而帮助这些项目统一和简化其依赖版本的声明。

pom.xml 中的体现

  • BOM本身 (my-company-bom/pom.xml):

    • 必须声明 <packaging>pom</packaging>
    • 其灵魂在于 <dependencyManagement> 部分,这里会声明大量的依赖及其精确的版本号。
    • 通常BOM中没有 <dependencies> (或极少),也没有 <modules>
    <project ...>
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example.boms</groupId>
        <artifactId>my-company-bom</artifactId>
        <version>1.2.0</version>
        <packaging>pom</packaging>
    
        <properties>
            <spring.version>5.3.20</spring.version>
            <jackson.version>2.13.3</jackson.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                    <version>${spring.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
    

<version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> </dependencyManagement> </project> ```

工作机制: 其他项目在其自身的 <dependencyManagement> 中,通过特殊的 <dependency> 声明(<type>pom</type><scope>import</scope>)来导入BOM。通过这种方式,目标BOM的 <dependencyManagement> 部分的声明会被“合并”到当前项目的 <dependencyManagement> 中。

<project ...>
    ...
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.example.boms</groupId>
                <artifactId>my-company-bom</artifactId>
                <version>1.2.0</version>
                <type>pom</type>
                <scope>import</scope> </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId> </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId> </dependency>
    </dependencies>
    ...
</project>

类比:“权威机构发布的推荐配件清单”。你的项目在“选配零件”(声明依赖)时,直接“参考引用”(import)这份清单,确保用到的都是推荐的、兼容的型号(版本)。

BOM 与父POM <dependencyManagement> 的区别

  • 父POM的 <dependencyManagement> 是通过继承自动传递给子模块的。
  • BOM的 <dependencyManagement> 是通过 <scope>import</scope> 被其他项目(可以是父POM,也可以是普通项目)主动导入的。
  • 一个项目只能有一个直接父POM,但它可以导入多个不同的BOM。

角色关系总结与 yudao-cloud 实践

角色 主要职责 pom.xml 核心体现 如何影响其他模块/项目
父POM 提供可继承的共享配置(版本、属性、插件管理等) 子模块使用 <parent> 指向它 子模块自动继承其 <properties>, <dependencyManagement>, <pluginManagement> 等配置
聚合POM 组织多个子模块,实现统一构建 自身包含 <modules> 列出子模块目录 通过Reactor机制管理并按顺序构建其列出的所有子模块
BOM 声明一套集中的、推荐的依赖版本清单 自身核心是 <dependencyManagement> 部分,<packaging>pom</packaging> 其他项目在其 <dependencyManagement> 中通过 <scope>import</scope> 导入其版本声明

在实际项目中,如 yudao-cloud

  • 其根 pom.xml (位于 yudao/ 目录下) 同时扮演父POM和聚合POM的角色。它既是所有子模块的 <parent>,也通过 <modules> 聚合了所有子模块。
  • yudao-cloudyudao-dependencies/pom.xml 是一个专用的BOM。这个BOM在其 <dependencyManagement> 中定义了大量第三方库和项目内部公共组件的版本。然后,根 pom.xml 在自己的 <dependencyManagement> 中通过 <scope>import</scope> 导入了这个 yudao-dependencies BOM,从而为整个项目体系提供统一、集中的依赖版本管理。

系列文章:

  • 《Maven入门:剖析POM核心与GAVP项目坐标》
  • 《Maven依赖管理精解:从<dependencies><dependencyManagement>与BOM实践》
  • 当前: 《Maven <packaging>pom</packaging>深度解析:父POM、聚合POM与BOM的三重身份》
  • 下一篇: 《玩转Maven多模块项目:继承、聚合与项目结构设计》