parent继承
本章是"继承与聚合"章节的起点。理解 parent 继承机制,是管理多模块项目、统一团队技术栈的前提。如果说单个 POM 是一家小店的账本,parent POM 就是连锁集团的财务制度——所有分店自动继承总部的规则,同时保留自己的特色经营。
核心机制
继承允许你定义一个"父 POM",其中包含所有子项目共享的配置。子项目通过 <parent> 标签引用父 POM,自动获得父 POM 中定义的依赖版本、插件版本、构建配置等。
parent 标签的作用
子 POM 通过 <parent> 标签声明继承关系:
<parent>
<groupId>com.feixiang</groupId>
<artifactId>feixiang-parent</artifactId>
<version>1.0.0</version>
<!-- 可选:如果父 POM 不在本地仓库或远程仓库 -->
<relativePath>../feixiang-parent/pom.xml</relativePath>
</parent>
关键规则:
- 父 POM 的
<packaging>必须是pom(它本身不产生构建产物,只作为配置模板) - 子 POM 继承父 POM 后,自己的
groupId和version可以省略(继承自父 POM) artifactId不能省略,因为每个模块必须有唯一标识
子 POM 继承父 POM 的内容清单
子 POM 会自动继承父 POM 中的以下内容:
| 继承内容 | 说明 |
|---|---|
groupId、version | 组织标识和版本号 |
properties | 自定义属性(如版本号变量) |
dependencies | 依赖列表(但子 POM 可覆盖) |
dependencyManagement | 依赖版本管理(子 POM 引用时无需写版本) |
plugins | 插件配置 |
pluginManagement | 插件版本管理 |
repositories | 仓库配置 |
build 中的部分配置 | 如 sourceDirectory(但通常不推荐覆盖) |
不继承的内容:
artifactId(每个模块必须独立)name、description(通常独立描述)dependencies中的具体依赖(如果父 POM 直接写在<dependencies>中,子 POM 会继承;但最佳实践是用<dependencyManagement>)
relativePath 的解析规则
<relativePath> 指定父 POM 的相对路径,默认值为 ../pom.xml。Maven 查找父 POM 的顺序是:
- 先按
relativePath查找本地文件 - 如果找不到,去本地仓库查找
- 如果还找不到,去远程仓库下载
生活类比:连锁酒店的运营手册
想象飞翔科技是一家连锁酒店集团:
- 父 POM = 集团运营手册。手册里规定了:所有分店必须使用同一品牌的床品(依赖版本)、同一套消防系统(插件版本)、统一的房价计算规则(properties)。
- 子 POM = 各城市分店的实际运营。北京店(
employee-system)和上海店(payroll-service)都遵循集团手册,但北京店可以额外提供故宫旅游服务(自己的依赖),上海店可以额外提供外滩接送服务(自己的插件配置)。 - relativePath = 分店经理找手册的方式。默认先去楼上集团办公室(
../pom.xml)找,找不到再打电话问总部(远程仓库)。
图示
上图展示了父子继承的核心逻辑:父 POM 集中管理共享配置,子 POM 自动继承并补充自己的特有配置。父 POM 的 packaging=pom 表明它本身不生成 JAR/WAR,纯粹是配置载体。
完整示例
场景
飞翔科技有两个项目:employee-system(员工系统)和 payroll-service(薪资服务)。CTO 大翔发现两个项目的 pom.xml 里重复声明了 Java 17、Spring Boot 3.2.0、compiler 插件 3.11.0 等相同配置。他要求架构师白歌提取一个父 POM,统一管理这些"集团标准"。
操作前:重复配置
employee-system/pom.xml:
<project>
<groupId>com.feixiang</groupId>
<artifactId>employee-system</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.0</spring-boot.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
</project>
payroll-service/pom.xml 有几乎相同的 <properties>、<build> 和 <dependencies> 片段。
操作步骤:提取父 POM
第一步:创建 feixiang-parent/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.feixiang</groupId>
<artifactId>feixiang-parent</artifactId>
<version>2.0.0</version>
<packaging>pom</packaging>
<name>飞翔科技 Parent POM</name>
<description>统一管理公司所有服务的共享配置</description>
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.0</spring-boot.version>
<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</pluginManagement>
</plugins>
</build>
</project>
第二步:修改 employee-system/pom.xml
<project>
<parent>
<groupId>com.feixiang</groupId>
<artifactId>feixiang-parent</artifactId>
<version>2.0.0</version>
<relativePath>../feixiang-parent/pom.xml</relativePath>
</parent>
<artifactId>employee-system</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 版本继承自父 POM 的 dependencyManagement,无需写 version -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 版本继承自父 POM 的 pluginManagement,无需写 version -->
</plugin>
</plugins>
</build>
</project>
第三步:payroll-service/pom.xml 做同样修改
操作结果及分析
继承的内容清单:
| 配置项 | 父 POM 定义 | 子 POM 状态 |
|---|---|---|
groupId | com.feixiang | 省略,自动继承 |
version | 2.0.0 | 省略,自动继承 |
java.version | 17 | 通过 ${java.version} 间接使用 |
spring-boot.version | 3.2.0 | 通过 ${spring-boot.version} 间接使用 |
compiler-plugin 版本 | 3.11.0 | 省略 <version>,自动继承 |
spring-boot-starter-web 版本 | 3.2.0 | 省略 <version>,自动继承 |
变化分析:
- 小崔维护
employee-system时,pom.xml从 60 行缩减到 25 行,只关注自己项目的特有依赖 - 白歌升级 Spring Boot 版本时,只需修改
feixiang-parent一处,两个子项目自动生效 - 李眉发现所有项目的构建行为完全一致,因为 compiler 插件的配置来自同一个源头
易错点与常见问题
误区一:父 POM 的 packaging 不是 pom
错误配置:
<artifactId>feixiang-parent</artifactId>
<packaging>jar</packaging> <!-- 错误! -->
后果:Maven 尝试为父项目生成 JAR 包,但父 POM 通常没有源代码(只有配置)。这会导致构建失败或产生空 JAR。父 POM 的唯一职责是承载共享配置,packaging 必须是 pom。
误区二:relativePath 写错,导致 Maven 去远程下载
错误配置:
<parent>
<groupId>com.feixiang</groupId>
<artifactId>feixiang-parent</artifactId>
<version>2.0.0</version>
<!-- 漏写 relativePath,且父 POM 未安装到本地仓库 -->
</parent>
后果:Maven 默认去 ../pom.xml 找父 POM。如果找不到,会去本地仓库找;如果还找不到,会去远程仓库下载。如果父 POM 还没发布到远程仓库,构建会报错:
[ERROR] Non-resolvable parent POM: Could not find artifact com.feixiang:feixiang-parent:pom:2.0.0
纠正:在本地开发时,先执行 mvn install 将父 POM 安装到本地仓库;或者显式写对 relativePath。
误区三:在父 POM 的 <dependencies> 里放具体依赖
错误配置(父 POM 中):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
后果:所有子 POM 都会强制继承这个依赖,即使某个子项目根本不需要 Spring Web。这会导致依赖膨胀、冲突增多。
纠正:在父 POM 中用 <dependencyManagement> 管理版本,子 POM 按需引用。<dependencyManagement> 只约束版本,不强制引入依赖。
小结
parent 继承是 Maven 管理多项目共享配置的核心机制。父 POM 通过 packaging=pom 声明自己为配置载体,子 POM 通过 <parent> 标签继承统一的依赖版本、插件版本和属性。使用 <dependencyManagement> 和 <pluginManagement> 可以避免强制依赖,让子项目按需引用。遵循继承机制,能显著减少重复配置、降低版本冲突风险、提升团队协作效率。
本章与全局的关系:本章讲解了"纵向"的父子继承关系。下一节将讲解"横向"的聚合(多模块)关系,以及继承与聚合的区别与配合。