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

    • 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章 常见问题与最佳实践

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

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 的顺序是:

  1. 先按 relativePath 查找本地文件
  2. 如果找不到,去本地仓库查找
  3. 如果还找不到,去远程仓库下载

生活类比:连锁酒店的运营手册

想象飞翔科技是一家连锁酒店集团:

  • 父 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 状态
groupIdcom.feixiang省略,自动继承
version2.0.0省略,自动继承
java.version17通过 ${java.version} 间接使用
spring-boot.version3.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> 可以避免强制依赖,让子项目按需引用。遵循继承机制,能显著减少重复配置、降低版本冲突风险、提升团队协作效率。

本章与全局的关系:本章讲解了"纵向"的父子继承关系。下一节将讲解"横向"的聚合(多模块)关系,以及继承与聚合的区别与配合。

下一页
聚合