Maven 核心概念与 POM 配置详解
Maven 围绕 POM(Project Object Model)构建了一套"约定优于配置"的工程模型。理解坐标、继承、聚合、BOM 四个核心概念,是掌握 Maven 的第一步。
坐标体系
Maven 用一组坐标唯一标识一个构件(artifact),也是依赖解析与仓库存储的寻址依据。
坐标 = groupId : artifactId : version
组织标识 模块标识 版本号| 坐标元素 | 说明 | 示例 |
|---|---|---|
| groupId | 组织/公司标识,反向域名 | com.example、org.springframework.boot |
| artifactId | 模块名称 | my-app、spring-boot-starter-web |
| version | 版本号,支持 -SNAPSHOT 后缀 | 1.0.0、3.3.2-SNAPSHOT |
| packaging | 打包方式(默认 jar) | jar、war、pom、maven-plugin |
| classifier | 附加限定(同版本不同产物) | sources、javadoc |
坐标同时决定构件在仓库中的存储路径:
~/.m2/repository/com/example/my-app/1.0.0/my-app-1.0.0.jar
└─groupId └─artifactId └─versionpackaging 决定 POM 的角色:pom 类型的项目不产出 jar,只做聚合或版本管理,这是父 POM 与 BOM 的基础。
POM 的四种关系
继承(Inheritance)
子模块通过 <parent> 继承父 POM 的配置,实现公共配置复用(依赖版本、插件、属性)。
parent (packaging=pom)
└── child-a(继承父的 properties/dependencyManagement/plugins)
└── child-b可继承的元素:groupId、version、properties、dependencyManagement、dependencies(直接继承全部依赖)、build 等。子模块通常不写 groupId 和 version,直接从父 POM 继承。
聚合(Aggregation)
聚合 POM 通过 <modules> 把多个模块组合在一起,一条命令构建全部模块。
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>mvn clean install # 在聚合根目录执行,一次构建所有 module继承与聚合的关系
| 维度 | 继承 | 聚合 |
|---|---|---|
| 目的 | 复用父 POM 配置 | 统一构建多模块 |
| 机制 | <parent> 引用 | <modules> 声明 |
| 方向 | 子 → 父 | 父 → 子 |
| 依赖 | 子模块必须继承 | 模块可独立存在 |
两者可以同时存在:父 POM 既提供继承(子模块 <parent> 指向它),又声明聚合(<modules> 包含子模块)。常见实践中父 POM 身兼两职。
dependencyManagement 与 BOM
dependencyManagement:统一版本
dependencyManagement 只声明版本约束,不引入依赖。子模块声明依赖时可以省略 version,由父 POM 统一裁决。
<!-- 父 POM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</dependencyManagement><!-- 子模块:省略 version -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
</dependencies><dependencies> 与 <dependencyManagement> 的关键区别:
| 位置 | 作用 | 子模块效果 |
|---|---|---|
<dependencies> | 实际引入依赖 | 全部继承 |
<dependencyManagement> | 只管理版本 | 子模块声明时才生效 |
BOM:跨项目版本分发
BOM(Bill of Materials)是一个 packaging 为 pom、只含 dependencyManagement 的独立构件,供多个项目 import 使用。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>company-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>import 的作用:把 BOM 内管理的版本"平铺"到当前 POM,实现多层级版本统一。Spring Boot 的 spring-boot-dependencies、Spring Cloud 的 spring-cloud-dependencies 都是 BOM 的典型代表。import 只能用于 dependencyManagement 且 type=pom。
POM 层级与属性
POM 解析顺序
有效 POM(Effective POM)= 超级 POM(默认值)
+ 父 POM(递归合并)
+ 当前 POM
+ 用户/全局 settings
+ Profile 激活配置mvn help:effective-pom 可以查看合并后的完整 POM,排查"配置为什么没生效"时最有用。
属性引用
| 属性类型 | 示例 | 说明 |
|---|---|---|
| 内置属性 | ${project.version}、${project.build.directory} | POM 中的元素 |
| 自定义属性 | ${java.version} | <properties> 中定义 |
| 系统属性 | ${user.home} | Java System.getProperties() |
| 环境变量 | ${env.JAVA_HOME} | 操作系统环境变量 |
| settings 属性 | ${settings.localRepository} | settings.xml 中的值 |
常见问题
- 子模块能覆盖父 POM 的依赖版本吗? 能。子模块显式声明
<version>会覆盖继承的dependencyManagement版本。 - BOM 之间的版本冲突怎么处理? 后 import 的 BOM 优先(与依赖冲突的最先声明优先相反,import 是按声明顺序后者覆盖前者)。
- 聚合与继承必须同时用吗? 不必须。小项目可以只继承不聚合,或用聚合根做批量构建而不提供继承。
- 如何调试 POM 合并问题?
mvn help:effective-pom输出合并结果,配合mvn validate -X查看详细解析日志。