乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

BOM

本章是"继承与聚合"章节的高级主题。BOM(Bill of Materials,物料清单)是 Maven 依赖管理的进阶武器,它解决了大型第三方生态(如 Spring Boot、Spring Cloud)的版本协调难题。理解 BOM 与普通 parent 的区别,是管理现代企业级项目依赖的必备技能。


核心机制

BOM 的核心特征可以概括为两点:

  1. only <dependencyManagement>:BOM 的核心职责只有一个——管理版本,不携带插件、不携带构建配置
  2. centralize dependency versions:BOM 是"版本清单",不是"配置模板"

BOM 的本质

BOM 本质上是一个特殊的 POM 文件,它的特点是:

  • packaging 为 pom
  • 只包含 <dependencyManagement>,不包含 <plugins>、<build> 等其他配置
  • 通过 <scope>import</scope> 被引入到项目的 <dependencyManagement> 中

import scope 的语法

BOM 不能通过 <parent> 继承,只能通过 import 范围导入:

<dependencyManagement>
    <dependencies>
        <!-- 导入 Spring Boot BOM -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

关键规则:

  • import scope 只能在 <dependencyManagement> 中使用
  • 必须同时声明 <type>pom</type>,因为导入的是一个 POM 文件,不是 JAR
  • 导入后,BOM 中管理的所有依赖版本自动在本项目中生效

BOM 与普通 parent 的区别

维度普通 Parent POMBOM
引入方式<parent> 继承<scope>import</scope> 导入
内容范围可包含插件、属性、构建配置等只包含 <dependencyManagement>
数量限制一个子 POM 只能有一个 parent一个 POM 可以导入多个 BOM
典型用途公司内部统一构建标准引入第三方生态的版本清单
版本控制子 POM 继承 parent 的版本子 POM 引用 BOM 中管理的版本

关键结论:Parent 是"公司制度",BOM 是"供应商产品目录"。一个项目只能遵循一套公司制度(一个 parent),但可以参考多份供应商目录(多个 BOM)。

Spring Boot Dependencies 示例

spring-boot-dependencies 是最著名的 BOM 之一。它内部管理了 200+ 个 Spring 生态相关依赖的版本:

<!-- spring-boot-dependencies-3.2.0.pom 内部片段 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.3</version>
        </dependency>
        <!-- 还有 200+ 个依赖... -->
    </dependencies>
</dependencyManagement>

当你的项目导入这个 BOM 后,引用其中任何依赖都无需写版本号:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 版本由 spring-boot-dependencies BOM 管理 -->
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <!-- 版本同样由 BOM 管理 -->
    </dependency>
</dependencies>

生活类比:装修公司的材料清单

想象你要装修一套房子(构建一个 Spring Boot 项目):

  • 普通 Parent POM = 装修公司的施工规范。规定了水电怎么走、墙面怎么刷、工期怎么排(插件配置、构建流程)。你只能选一家装修公司(一个 parent)。
  • BOM = 建材供应商的产品目录。比如"宜家 2024 全屋套餐清单",里面列出了沙发、餐桌、灯具的型号和价格(依赖版本)。你可以同时参考宜家的清单和本地家具城的清单(多个 BOM),从中挑选合适的家具。
  • import scope = 把供应商的产品目录放进你的购物车。你不需要买下整个宜家商场(继承整个 POM),只需要把目录复印一份,按上面的型号选购(引用版本)。

如果没有 BOM,你要逐个去查每个 Spring 依赖的兼容版本——就像没有产品目录时,你得亲自去工厂确认"这款沙发和这款茶几是否配套"。


图示

上图展示了 BOM 导入机制的核心逻辑:项目 POM 通过 <parent> 继承公司内部的构建规范(父 POM),同时通过 <scope>import</scope> 引入多个第三方 BOM 的版本清单。最终依赖列表中的版本由 BOM 统一提供,无需在每个依赖上硬编码。


完整示例

场景

飞翔科技的 employee-system 要引入 Spring Boot 3.2.0 和 Spring Cloud 2023.0.0。架构师白歌发现:Spring Boot 和 Spring Cloud 有严格的版本对应关系,手动管理容易出错。他决定用 BOM 来统一控制。

操作前:手动管理版本(易错)

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>4.1.0</version>  <!-- 需要手动确认与 Spring Boot 3.2.0 兼容 -->
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.3</version>  <!-- 需要手动确认与 Spring Boot 3.2.0 兼容 -->
    </dependency>
</dependencies>

问题:

  • 小崔升级 Spring Boot 到 3.3.0 时,不知道 Spring Cloud Gateway 应该升级到哪个版本
  • 黄俪引入 spring-boot-starter-data-redis 时,忘了写版本号,Maven 报错
  • 李眉排查生产环境问题时,发现 jackson-databind 版本与 Spring Boot 内置版本冲突

操作步骤:导入 BOM

第一步:在 feixiang-parent 中导入 BOM(推荐在父 POM 统一导入)

<dependencyManagement>
    <dependencies>
        <!-- Spring Boot BOM -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Spring Cloud BOM -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2023.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

第二步:子项目按需引用,不写版本号

employee-system/pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

操作结果:BOM 与普通 parent 的区别

使用 BOM 后的版本控制:

依赖版本来源实际版本
spring-boot-starter-webspring-boot-dependencies BOM3.2.0
spring-boot-starter-data-redisspring-boot-dependencies BOM3.2.0
spring-cloud-starter-gatewayspring-cloud-dependencies BOM4.1.0
jackson-databind(传递依赖)spring-boot-dependencies BOM2.15.3

变化分析:

  • 小崔引入新的 Spring Boot Starter 时,无需查文档找版本号,直接写 groupId 和 artifactId 即可
  • 白歌升级 Spring Boot 时,只需修改 spring-boot-dependencies 的导入版本,所有相关依赖自动对齐
  • 李眉检查依赖树时,发现所有 Spring 生态的版本来自同一个 BOM,没有冲突

BOM 与普通 parent 的职责分离:

职责由谁承担具体内容
公司构建规范feixiang-parent(普通 parent)Java 17、compiler 插件 3.11.0、UTF-8
第三方生态版本spring-boot-dependencies(BOM)Spring Boot 3.2.0、Jackson 2.15.3
微服务生态版本spring-cloud-dependencies(BOM)Gateway 4.1.0、OpenFeign 4.1.0

易错点与常见问题

误区一:import scope 用在 <dependencies> 中

错误配置:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>3.2.0</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>

后果:Maven 报错 import scope 只能用于 dependencyManagement 中。因为 import 的作用是"导入版本清单",而不是"引入一个依赖"。BOM 本身不是项目的运行时依赖,构建产物中不应该包含 BOM。

纠正:import 必须写在 <dependencyManagement> 下,且通常放在父 POM 中统一管理。

误区二:把 BOM 当作 parent 继承

错误配置:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>3.2.0</version>
</parent>

后果:虽然技术上可行(因为 spring-boot-dependencies 的 packaging 确实是 pom),但这样做会丢失你自己的 parent 继承链。你的项目无法继承公司内部的 feixiang-parent,导致构建规范(如 compiler 插件配置、仓库地址)全部丢失。

纠正:BOM 用 import,parent 用 <parent>。两者各司其职:

  • <parent> 留给公司/团队内部的父 POM
  • import 留给第三方 BOM

误区三:导入了 BOM,但某个依赖仍然写了版本号

配置:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.1.0</version>  <!-- 覆盖了 BOM 的版本 -->
    </dependency>
</dependencies>

后果:Maven 优先使用依赖上显式声明的版本(3.1.0),而不是 BOM 管理的版本(3.2.0)。这会导致版本不一致,破坏 BOM 的统一管理价值。

纠正:导入 BOM 后,被管理的依赖不要再写 <version>。如果确实需要覆盖某个依赖的版本,应在 <dependencyManagement> 中显式声明,而不是在 <dependencies> 中硬编码。


小结

BOM(Bill of Materials)是 Maven 管理复杂第三方生态版本的进阶工具。它通过 <scope>import</scope> 将版本清单导入项目的 <dependencyManagement>,实现了"一份清单、多处引用"的版本协调。BOM 与普通 parent 的核心区别在于:BOM 只管理依赖版本,不管理构建配置;一个项目可以导入多个 BOM,但只能继承一个 parent。在 Spring Boot、Spring Cloud 等现代 Java 生态中,BOM 已成为事实上的标准版本管理方式。

本章与全局的关系:本章结束了"继承与聚合"章节,也完成了 Maven 入门教程的核心内容。通过 parent 继承、聚合、properties 和 BOM 四个机制,你已经掌握了从单模块到多模块、从简单项目到企业级平台的 Maven 项目管理能力。

上一页
聚合
下一页
properties