POM
本章承接"安装与配置"三部曲,正式进入 Maven 的项目核心。如果说安装和环境配置解决了"Maven 怎么跑"的问题,那么 POM 就是解决"项目是什么"的问题——它是 Maven 理解项目的唯一入口。
核心机制
项目对象模型(POM)是 Maven 中工作的基本单元。它是项目的 XML 表示,包含构建项目所需的全部信息。这意味着:
- 没有 POM,Maven 不工作。你在任何目录执行
mvn命令,Maven 首先要找到pom.xml,否则报错 - POM 是项目的"唯一真相源"。项目的名字、版本、依赖、构建方式,全部以 POM 为准,不以 IDE 的配置为准
- POM 是"声明式"的。你告诉 Maven"我想要什么",而不是"怎么做"。具体怎么做,由 Maven 根据 POM 的声明自动推导
POM 是项目的"DNA"
如果把一个 Maven 项目比作一个生物体,那么 pom.xml 就是它的 DNA 序列:
| 生物 DNA | POM 对应 | 作用 |
|---|---|---|
| 物种标识基因 | groupId + artifactId + version | 唯一标识这个项目是谁 |
| 遗传信息 | dependencies | 这个项目"继承"了哪些外部能力 |
| 细胞结构 | build / plugins | 这个项目怎么"生长"(编译、打包) |
| 环境适应性 | profiles | 在不同环境下(开发/测试/生产)的不同表现 |
就像 DNA 决定了生物的所有特征,POM 决定了项目的所有构建行为。两个项目的 POM 如果完全一样,那么无论谁在什么机器上构建,产物都完全一致——这就是 Maven 追求的可复现构建(Reproducible Build)。
modelVersion:POM 的"语法版本"
每个 pom.xml 的根元素 <project> 下,第一个子元素必须是 <modelVersion>。它表示当前 POM 文件遵循的 POM 模型版本,不是项目的版本。
<modelVersion>4.0.0</modelVersion>
- Maven 2.x、3.x 统一使用
4.0.0,这是 2009 年定下的标准,至今未变 - 它告诉 Maven 引擎:"请用 4.0.0 版本的规则来解析这个文件"
- 如果写错(如
4.0或3.0.0),Maven 会拒绝解析,直接报错
可以把 modelVersion 理解为 POM 文件的"语法版本",类似 HTML 的 <!DOCTYPE html>。它与你项目的业务版本(1.0.0)完全无关。
最小 POM:Maven 的"最低生存需求"
一个合法的 pom.xml 最少只需要三个元素:
<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>minimal-demo</artifactId>
<version>1.0.0</version>
</project>
这个最小 POM 已经足以让 Maven 识别项目并执行基本构建。Maven 会为缺失的元素填充**超级 POM(Super POM)**中的默认值:
packaging默认为jarsourceDirectory默认为src/main/javatestSourceDirectory默认为src/test/javaoutputDirectory默认为target/classes
超级 POM 是 Maven 内置的一个"隐形模板",所有项目的 POM 都隐式继承它。它定义了 Maven 的"约定"默认值,是"约定优于配置"思想的工程实现。
图示
上图展示了 POM 的双层继承结构:项目 POM 只声明项目的独特信息(坐标、依赖),而所有"通用规则"(目录结构、插件绑定)由超级 POM 提供。两者合并后,形成完整的构建配置。这也是 Maven 配置精简的根本原因——你不需要重复声明行业共识。
完整示例
场景
飞翔科技要启动一个新项目 employee-system(员工信息管理系统)。CTO 大翔要求项目必须从零开始建立标准的 Maven 结构,方便后续团队协作。架构师白歌负责创建初始 POM,后端小崔负责验证构建。
操作前:空目录
小崔在本地创建了一个空目录:
C:\projects\employee-system/
里面什么都没有。白歌说:"先别急着写 Java 代码,先把 POM 建好。POM 是项目的地基。"
操作步骤
步骤 1:创建最小 POM
白歌在 employee-system/ 目录下创建 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>employee-system</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>员工信息管理系统</name>
<description>飞翔科技内部员工信息管理与查询系统</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.21</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
步骤 2:创建标准目录结构
小崔根据 POM 的隐式约定,创建标准目录:
mkdir -p src/main/java/com/feixiang/employee
mkdir -p src/main/resources
mkdir -p src/test/java/com/feixiang/employee
mkdir -p src/test/resources
目录结构变为:
employee-system/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── feixiang/
│ │ │ └── employee/
│ │ └── resources/
│ └── test/
│ ├── java/
│ └── resources/
步骤 3:验证构建
小崔执行编译:
mvn compile
预期输出:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< com.feixiang:employee-system >------------------
[INFO] Building 员工信息管理系统 1.0.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.3.1:resources (default-resources) @ employee-system ---
[INFO] Copying 0 resource from src\main\resources to target\classes
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ employee-system ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 0 source files to target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.345 s
[INFO] Finished at: 2024-01-15T09:30:00+08:00
[INFO] ------------------------------------------------------------------------
操作结果及分析
| 输出项 | 含义 | 来源 |
|---|---|---|
com.feixiang:employee-system | 项目坐标 | pom.xml 中的 GAV |
员工信息管理系统 | 项目可读名称 | pom.xml 中的 <name> |
jar | 打包类型 | pom.xml 中的 <packaging> |
maven-resources-plugin:3.3.1 | 资源复制插件 | 超级 POM 默认绑定 |
maven-compiler-plugin:3.11.0 | 编译插件 | 超级 POM 默认绑定 |
target\classes | 编译输出目录 | 超级 POM 默认路径 |
注意:小崔没有在 pom.xml 里写任何关于"资源复制"或"编译器版本"的配置,但 Maven 自动调用了 maven-resources-plugin 和 maven-compiler-plugin。这就是超级 POM 的力量——它预定义了标准生命周期与插件的绑定关系。
易错点与常见问题
误区一:modelVersion 写成项目版本
错误配置:
<modelVersion>1.0.0</modelVersion> <!-- ❌ 这是项目版本,不是模型版本 -->
后果:Maven 解析 POM 时,发现 modelVersion 不是它认识的 4.0.0,直接报错:
[ERROR] 'modelVersion' must be one of 4.0.0 but is '1.0.0'.
纠正:modelVersion 永远是 4.0.0,与项目业务版本无关:
<modelVersion>4.0.0</modelVersion> <!-- ✅ POM 模型版本 -->
<version>1.0.0-SNAPSHOT</version> <!-- ✅ 项目业务版本 -->
误区二:省略 XML 命名空间
错误配置:
<project> <!-- ❌ 缺少 xmlns 命名空间 -->
<modelVersion>4.0.0</modelVersion>
...
</project>
后果:某些严格校验的 Maven 插件(如 maven-enforcer-plugin)或 CI 环境会报 Schema 验证错误。虽然 Maven 核心引擎有时能容忍,但这是不规范的写法。
纠正:始终携带完整的命名空间声明:
<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">
误区三:认为 POM 只是"依赖列表"
错误认知:"pom.xml 不就是写依赖的地方吗?别的标签我不关心。"
纠正:dependencies 只是 POM 的冰山一角。一个完整的 POM 还管理着:
- 项目身份:
groupId、artifactId、version、name、description - 构建行为:
build、plugins、pluginManagement - 环境适配:
profiles(开发/测试/生产差异化配置) - 项目关系:
parent(继承)、modules(聚合)、dependencyManagement - 元信息:
licenses、developers、scm(版本控制地址)
POM 是项目的完整声明,依赖只是其中一部分。如果你只把 POM 当依赖清单用,就错过了 Maven 管理项目关系的强大能力。
小结
POM(Project Object Model)是 Maven 的工作基本单元,pom.xml 是项目的"DNA"和"唯一真相源"。它通过 modelVersion 声明文件语法版本,通过 GAV 坐标声明项目身份,通过 dependencies 声明外部依赖,其余构建规则由超级 POM 提供默认值。理解 POM 的层次结构(超级 POM + 项目 POM),是理解继承、聚合、依赖管理等高级机制的基础。
本章与全局的关系:本章建立了项目的"身份档案"。下一章"GAV 坐标"将深入讲解 groupId、artifactId、version 三要素,揭示 Maven 如何通过"坐标系统"在茫茫仓库中唯一锁定一个项目。