【工具】Maven使用之pom.xml文件

Maven使用之POM文件

pom.xml文件在项目目录中所处的位置?

它在项目根目录下,与src文件夹同级。

pom.xml文件在Maven项目中所处的地位?

pom.xml 在 Maven 项目里的地位,可以理解成:

它是 Maven 项目的"总说明书 + 构建配置中心 + 项目模型定义"。

Maven 几乎所有动作,都是先读 pom.xml 再决定怎么干。

如果没有 pom.xml

bash 复制代码
mvn compile
mvn package
mvn install

通常直接失败:

text 复制代码
The goal you specified requires a project to execute
but there is no POM in this directory

说明 Maven 不知道:

  • 你是谁(项目信息)
  • 代码在哪
  • 依赖有哪些
  • 怎么编译
  • 怎么打包

可以把 Maven 项目想象成一个工厂:

text 复制代码
源码         → 原材料
依赖         → 外购零件
插件         → 机器设备
Maven        → 工厂调度系统
pom.xml      → 工厂总设计图

没有设计图,工厂不知道生产什么。


一、从结构上看:它是项目的根配置

典型目录:

text 复制代码
hello-world
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   └── test
└── target

其中:

text 复制代码
pom.xml
↑
整个项目的中心

二、从执行流程看:它是 Maven 的输入

执行:

bash 复制代码
mvn package

内部大概:

text 复制代码
读取 pom.xml
↓
生成项目模型(Project)
↓
解析继承
↓
解析依赖
↓
确定生命周期
↓
绑定插件
↓
执行目标
↓
输出结果

所以:

text 复制代码
pom.xml
↓
Project Object Model
↓
Maven运行依据

这里 POM 的全称就是:

Project Object Model(项目对象模型)

意思不是"配置文件"。

而是:

Maven把项目抽象成一个对象模型。


三、它主要定义哪些内容

1 项目身份

决定项目是谁。

xml 复制代码
<groupId>com.demo</groupId>
<artifactId>hello</artifactId>
<version>1.0</version>

组成:

text 复制代码
GAV

groupId
artifactId
version

唯一标识一个构件。

例如:

text 复制代码
com.demo:hello:1.0

2 项目依赖

定义需要哪些 jar。

xml 复制代码
<dependencies>
    <dependency>
        ...
    </dependency>
</dependencies>

作用:

text 复制代码
告诉Maven:
编译时请把这些库准备好

3 构建规则

定义怎么编译。

xml 复制代码
<build>

例如:

  • 用哪个编译插件
  • Java版本
  • 打包方式

4 生命周期行为

例如:

bash 复制代码
mvn compile
mvn test
mvn package
mvn install

每一步执行什么插件。


5 多模块关系

父项目:

xml 复制代码
<modules>

子项目:

xml 复制代码
<parent>

决定整个工程结构。


四、从重要性看:它比代码更像项目的大脑

有时候:

text 复制代码
代码没变
pom改了
整个项目行为变了

例如:

改:

xml 复制代码
<packaging>jar</packaging>

变:

xml 复制代码
<packaging>war</packaging>

项目瞬间从:

text 复制代码
普通Java应用
↓
Web应用

再比如:

改依赖:

xml 复制代码
spring 5
↓
spring 6

整个运行结果都可能变化。


一句话记忆:

text 复制代码
源码决定"程序做什么"
pom.xml决定"项目怎么被构建出来"

再往深一层,可以继续问:

为什么 Maven 不直接读取目录,而非要先把 pom.xml 转成 Project Object Model 对象?

那个问题会进入 Maven 的核心架构(Model → Lifecycle → Plugin → Artifact)。

pom.xml文件包含的内容

最精简的pom文件:

java 复制代码
<?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.example</groupId>
    <artifactId>hello-world-maven-ide</artifactId>
    <version>1.0-SNAPSHOT</version>


</project>

pom文件解析

这是一个最精简的 Maven 项目 pom.xml,我逐行给你拆解含义:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
  • XML 文件声明,版本 1.0,编码 UTF-8。
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">
  • 根标签 <project>
  • xmlns 声明 Maven POM 命名空间
  • xsi:schemaLocation 指定 XML 约束文件,用于 IDE 校验语法
xml 复制代码
<modelVersion>4.0.0</modelVersion>
  • POM 模型版本
  • 目前 Maven 统一使用 4.0.0,几乎不会改。
xml 复制代码
<groupId>com.example</groupId>
  • 组织/公司域名(倒序)
  • 类似 Java 包名前缀,这里是示例域名 com.example
xml 复制代码
<artifactId>hello-world-maven-ide</artifactId>
  • 项目/模块名称
  • 这个项目的名字:hello-world-maven-ide
xml 复制代码
<version>1.0-SNAPSHOT</version>
  • 版本号
  • 1.0:主版本
  • SNAPSHOT:表示开发中、快照版本,还未正式发布
xml 复制代码
</project>
  • 根标签结束。

整体总结

这是一个空的、无任何依赖、无插件的最小 Maven 项目配置:

  • 坐标:com.example:hello-world-maven-ide:1.0-SNAPSHOT
  • 作用:仅用来标识项目,不能运行任何代码,也没有引入 Spring、Servlet 等任何依赖。

如果你需要,我可以帮你:

  • 加上 JUnit 测试依赖
  • 加上 Maven 编译插件
  • 改成可运行的 Java 项目

丰富pom文件内容

我给你直接改成可编译、可运行、带测试的完整 pom.xml,你直接覆盖原文件即可:

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.example</groupId>
    <artifactId>hello-world-maven-ide</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 指定JDK版本,解决编码和编译问题 -->
    <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>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建插件:打包、编译 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

加了哪些东西:

  1. <properties>

    • 统一指定 JDK 版本(这里用 11,你也可以改成 8 / 17)
    • 设置编码为 UTF-8,避免中文乱码
  2. <dependencies>

    • 加入了 JUnit 4 测试依赖,可以写单元测试
  3. <build> 插件

    • maven-compiler-plugin:确保 Maven 用指定 JDK 编译

配套使用建议:

  • 目录结构:

    复制代码
    src
    ├── main
    │   └── java
    │       └── com
    │           └── example
    │               └── App.java
    └── test
        └── java
            └── com
                └── example
                    └── AppTest.java
  • 执行命令:

    • mvn compile 编译
    • mvn test 运行测试
    • mvn package 打成 jar 包

Maven拉依赖,是拉什么,是从哪儿拉到哪儿?

Maven拉依赖,是读取pom.xml文件中的<dependencies>标签下的<dependency>内容,获取依赖的GAV坐标。


Maven 拉依赖,本质上是:

根据 pom.xml 中声明的依赖坐标(GAV),从远程仓库下载对应的构件(artifact),保存到本地仓库,再加入项目构建路径(classpath)。

例如:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

1. Maven 拉的是什么?

不是拉源码,而是拉:

(1)jar 包(最常见)

真正运行代码:

text 复制代码
junit-4.13.2.jar

里面是:

text 复制代码
.class
META-INF
资源文件

(2)POM 文件

描述这个依赖自身还依赖谁。

例如:

text 复制代码
junit-4.13.2.pom

内容类似:

xml 复制代码
<dependencies>
    <dependency>
        ...
    </dependency>
</dependencies>

Maven 会继续解析。

这叫:

传递依赖(Transitive Dependency)


(3)校验文件(可选)

例如:

text 复制代码
.sha1
.md5

用于验证下载完整性。


2. GAV 坐标是什么?

Maven 用 GAV 唯一定位依赖。

text 复制代码
G = groupId
A = artifactId
V = version

例如:

xml 复制代码
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>

对应:

text 复制代码
junit:junit:4.13.2

像身份证:

text 复制代码
组织:项目:版本

3. 从哪儿拉?

优先级一般:

text 复制代码
① 本地仓库
↓

② 私服(如果配置)
↓

③ 中央仓库

本地仓库

默认:

Mac/Linux:

text 复制代码
~/.m2/repository

例如:

text 复制代码
~/.m2/repository/junit/junit/4.13.2/

里面:

text 复制代码
junit-4.13.2.jar
junit-4.13.2.pom

私服(企业常用)

例如:

text 复制代码
Nexus
Artifactory

公司统一缓存依赖。


中央仓库

默认:

text 复制代码
https://repo.maven.apache.org/maven2

4. 拉到哪儿?

最终放到:

text 复制代码
本地仓库 ~/.m2/repository

目录结构由 GAV 自动生成:

依赖:

text 复制代码
junit:junit:4.13.2

映射:

text 复制代码
~/.m2/repository
└── junit
    └── junit
        └── 4.13.2
            ├── junit-4.13.2.jar
            └── junit-4.13.2.pom

5. 拉完之后怎么用?

下载结束后。

Maven:

text 复制代码
jar
↓
加入 classpath
↓
javac 编译
↓
java 运行

于是代码能:

java 复制代码
import org.junit.Test;

否则:

text 复制代码
package org.junit does not exist

6. 实际执行过程(以 mvn compile 为例)

text 复制代码
读取 pom.xml
↓

解析 dependencies
↓

得到 GAV
↓

查 ~/.m2
↓

没有
↓

请求远程仓库
↓

下载 jar + pom
↓

存入 ~/.m2
↓

递归下载传递依赖
↓

加入 classpath
↓

开始编译

所以一句话总结:

Maven 拉依赖,不是"把代码拷到项目里",而是根据 pom 中的 GAV,把构件(jar、pom 等)从远程仓库下载到本地仓库,再挂到当前项目的 classpath 上供编译和运行使用。

pom.xml文件的作用?从实际用到的地方入手。

什么时候会读取pom.xml文件?

这个问题问到 Maven 的执行时机了。

先给结论:

几乎所有 Maven 命令开始执行时,第一步都是读取 pom.xml

因为 Maven 要先知道:

text 复制代码
这是哪个项目?
依赖是什么?
执行哪个生命周期?
插件怎么配置?

不知道这些,就没法继续。


1. 执行 Maven 命令时(最常见)

例如:

bash 复制代码
mvn compile

内部大概:

text 复制代码
启动 Maven
↓
找当前目录 pom.xml
↓
读取并解析
↓
生成 Project Model
↓
解析依赖
↓
执行 compile

再比如:

bash 复制代码
mvn package
mvn install
mvn test
mvn clean

都会先读 pom.xml

所以:

bash 复制代码
mvn compile

不是:

text 复制代码
直接编译

而是:

text 复制代码
先读pom
再编译

2. IDEA 导入 / 打开 Maven 项目时

例如:

text 复制代码
File
↓
Open
↓
选择项目目录

如果发现:

text 复制代码
pom.xml

IDEA 会:

text 复制代码
读取pom
↓
解析依赖
↓
生成模块
↓
建立索引
↓
下载依赖

所以第一次打开项目常看到:

text 复制代码
Import Maven Project

其实就是:

text 复制代码
导入 pom.xml

3. 修改 pom.xml 时

例如你改:

xml 复制代码
<dependency>

保存。

IDEA 通常会:

text 复制代码
检测pom变化
↓
重新导入
↓
重新解析依赖

你会看到:

text 复制代码
Reload Maven Project

4. 下载依赖时

例如:

bash 复制代码
mvn dependency:tree

过程:

text 复制代码
读pom
↓
拿dependencies
↓
解析依赖树

5. 多模块项目构建时

假设:

text 复制代码
project
├── pom.xml
├── order
│   └── pom.xml
└── user
    └── pom.xml

执行:

bash 复制代码
mvn package

会:

text 复制代码
读父pom
↓
读子pom
↓
组装项目模型
↓
开始构建

一个容易误解的点

读取 pom.xml ≠ 每次都重新下载依赖。

例如:

第一次:

text 复制代码
读pom
↓
发现缺依赖
↓
下载

第二次:

text 复制代码
读pom
↓
发现本地已有
↓
直接使用

所以:

text 复制代码
读pom:几乎每次执行
下载依赖:按需执行

最后给一句记忆:

text 复制代码
Maven 的运行入口通常不是源码,而是 pom.xml。
源码是材料,pom 是施工图。

你前面已经串起来了:

mvn compile → 读取 pom → 解析依赖 → 调插件 → javac → class

再往下一层,就是:

Maven 是怎么找到当前目录对应的 pom.xml 的(工作目录、-f 参数、父子 POM 查找)