在 Spring Boot 中,官方项目几乎都采用继承父 POM 的方式引入,即:
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
这个设计不是偶然的,它解决了 Spring Boot 依赖管理中最核心的两个问题:版本统一 和插件预置。
版本统一:dependencyManagement
spring-boot-starter-parent 中定义了一个巨大的 <dependencyManagement>,锁定了数百个常用库的版本号------Spring 各模块、第三方库(如 Jackson、MyBatis、Hibernate)、数据库驱动等。子模块引入依赖时不需要写版本号,由父 POM 统一管理。
手动管理版本号时,经常出现 A 依赖需要 2.3.1 版本,B 依赖依赖 2.3.5 版本,两个库之间版本不匹配导致诡异报错。继承 starter-parent 后,Spring Boot 团队已经为所有 Starter 依赖完成了兼容性测试,你只需要关注功能,不需要操心版本之间的冲突。
插件预置:maven-plugin
spring-boot-maven-plugin 在父 POM 中已经配置好了。如果手动引入 Spring Boot,需要自己写这个插件的配置,包括 repackage 目标的绑定、mainClass 的指定等。继承父 POM 后,这些全有了,子模块不需要额外配置。
属性定制
父 POM 通过 <properties> 定义了 Java 版本、编码格式等常用属性。子模块可以覆盖这些属性,比如将 Java 版本从 8 改成 17,只需要在子 POM 中重新定义 java.version 即可。
使用场景的限制
继承方式有一个天然限制:Maven 只允许单继承 。如果项目已经继承了其他父 POM(比如公司内部的公共父 POM),就无法再继承 spring-boot-starter-parent。
这种情况下可以用 BOM(Bill of Materials)方式替代:
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.18</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
BOM 方式只提供依赖版本管理,不提供插件预置。spring-boot-maven-plugin 需要在子模块中单独配置。两种方式的对比如下:
| 对比点 | 继承 parent | BOM 导入 |
|---|---|---|
| 依赖版本管理 | ✅ 有 | ✅ 有 |
| 插件预置 | ✅ 有 | ❌ 需手动配置 |
| Java 版本默认值 | ✅ 有 | ❌ 需手动设置 |
| 资源过滤默认配置 | ✅ 有 | ❌ 需手动配置 |
| 是否支持多继承 | ❌ 单继承限制 | ✅ 可多个 BOM 叠加 |
继承方式的本质
spring-boot-starter-parent 是一个标准的 Maven 父 POM,它自身又继承了 spring-boot-dependencies。前者负责插件配置和属性管理,后者负责依赖版本锁定。两层结构分离了"版本管理"和"构建配置"两个职责。
当你在子 POM 中声明一个依赖不写版本号时,Maven 会沿着父子链向上查找,最终在 spring-boot-dependencies 中找到对应的版本。当执行 mvn package 时,spring-boot-maven-plugin 会执行 repackage 目标,生成可执行的 Fat Jar。
继承方式让 Spring Boot 项目的 pom.xml 保持极简,你把核心精力放在业务依赖上,而不是构建配置的细节。这也是 Spring Boot "约定优于配置"理念在构建层面的体现。