一、Maven 是什么?

在 Java 开发中,Maven 是一个非常重要的工具。

它不是 Java 语法,也不是 JDK 的一部分,而是一个专门用来管理 Java 项目的工具。

简单来说,Maven 主要做三件事:

  1. 管理依赖

  2. 统一项目结构

  3. 自动构建项目

如果用一句话概括:

Maven 是 Java 项目的“项目管家”,它可以帮我们自动下载第三方 jar 包、管理项目结构、编译代码、运行测试、打包项目。


二、为什么 Java 项目需要 Maven?

在没有 Maven 之前,Java 项目经常会遇到这些问题:

1. 项目需要很多第三方 jar 包,需要手动下载。
2. jar 包之间还有依赖关系,一个 jar 又依赖另一个 jar。
3. jar 包版本容易冲突。
4. 不同人电脑上的项目结构不统一。
5. 项目打包过程复杂。
6. 换一台电脑之后,项目可能跑不起来。
7. 团队协作时,不知道别人到底用了哪些依赖。

比如我们做一个 Java Web 项目,可能需要:

Spring Boot
Spring MVC
MyBatis
MySQL Driver
Lombok
Jackson
JUnit
Logback
Redis Client
Swagger

如果没有 Maven,我们可能要自己一个个去网上下载 jar 包,然后手动导入项目。

这样做非常麻烦,而且很容易出错。

有了 Maven 之后,我们只需要在 pom.xml 文件中写清楚需要什么依赖,Maven 就会自动帮我们下载。

例如:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.4.0</version>
</dependency>

这段配置的意思是:

当前项目需要使用 MySQL 驱动,版本是 8.4.0。

然后 Maven 会自动下载对应的 jar 包,并把它加入到项目中。


三、Maven 在 Java 体系中的位置

很多初学者容易把 JDK、IDEA、Maven、Spring Boot 混在一起。

它们的关系可以这样理解:

名称 作用
JDK Java 开发工具包,负责编译和运行 Java 程序
IDEA Java 开发工具,用来写代码、运行项目、调试程序
Maven 项目管理和构建工具,负责依赖下载、编译、测试、打包
Spring Boot Java 后端开发框架,用来快速开发 Web 后端项目
pom.xml Maven 项目的核心配置文件

可以用一个比喻来理解:

JDK = 厨具和灶台
Java 代码 = 食材
第三方 jar 包 = 调料
pom.xml = 菜谱
Maven = 按菜谱自动准备调料、处理食材、完成打包的人
IDEA = 厨房工作台
Spring Boot = 一套成熟的做菜方案

所以 Maven 的本质不是写业务代码,而是管理项目。


四、Maven 的核心作用

1. 依赖管理

Maven 最重要的作用之一就是依赖管理。

什么是依赖?

简单说:

你的项目需要使用别人写好的代码库,这些代码库就是依赖。

比如你要连接 MySQL 数据库,就需要 MySQL 驱动。

你要开发 Web 接口,就需要 Spring Web。

你要写单元测试,就需要 JUnit。

这些都属于项目依赖。

在 Maven 中,依赖写在 pom.xml 文件中:

<dependencies>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.4.0</version>
    </dependency>
</dependencies>

Maven 看到这段配置后,会自动去远程仓库下载 jar 包。


2. 统一项目结构

Maven 对项目结构有一套默认规范。

一个标准 Maven 项目通常长这样:

my-project
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com/example
    │   │       └── Main.java
    │   └── resources
    │       └── application.yml
    └── test
        └── java
            └── com/example
                └── MainTest.java

各目录含义如下:

路径 作用
pom.xml Maven 项目的核心配置文件
src/main/java 存放正式 Java 源代码
src/main/resources 存放配置文件、静态资源等
src/test/java 存放测试代码
src/test/resources 存放测试相关资源
target Maven 编译和打包后的输出目录

例如 Spring Boot 项目中常见:

src/main/resources/application.yml

这个文件通常用来配置数据库、端口号、Redis、日志等信息。


3. 项目构建

所谓构建,不只是运行项目。

构建包括:

清理旧文件
编译源代码
处理资源文件
运行测试
打包 jar 或 war
安装到本地仓库
部署到远程仓库

Maven 可以通过命令完成这些操作。

常见命令如下:

mvn clean

清理旧的构建结果,也就是删除 target 目录。

mvn compile

编译项目源代码。

mvn test

运行测试代码。

mvn package

将项目打包成 jar 或 war。

mvn install

将当前项目打包后安装到本地 Maven 仓库。

mvn deploy

将项目发布到远程仓库,通常用于公司内部公共模块发布。


五、Maven 工作流程图

下面用 Mermaid 画一个 Maven 的基本工作流程。

flowchart TD
    A[开发者编写 Java 代码] --> B[配置 pom.xml]
    B --> C[执行 Maven 命令]
    C --> D{本地仓库是否已有依赖?}
    D -- 有 --> E[直接使用本地依赖]
    D -- 没有 --> F[从远程仓库下载依赖]
    F --> G[保存到本地仓库]
    E --> H[编译源代码]
    G --> H
    H --> I[运行测试]
    I --> J[打包 jar/war]
    J --> K[生成 target 目录]

六、Maven 的核心文件:pom.xml

1. 什么是 pom.xml?

Maven 项目最重要的文件就是:

pom.xml

POM 是:

Project Object Model
项目对象模型

你可以把 pom.xml 理解成 Maven 项目的说明书。

它告诉 Maven:

这个项目叫什么?
这个项目属于谁?
这个项目是什么版本?
这个项目需要哪些依赖?
这个项目用哪个 JDK 编译?
这个项目如何打包?
这个项目需要哪些插件?

2. 最简单的 pom.xml

一个最基础的 Maven 项目 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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>

</project>

3. groupId、artifactId、version 是什么?

Maven 中最重要的三个坐标是:

groupId
artifactId
version

它们合起来叫做 Maven 坐标。

也叫 GAV 坐标。

G = groupId
A = artifactId
V = version

一个依赖可以通过这三个坐标唯一确定。


4. groupId

groupId 通常表示组织、公司、团队或者个人。

一般使用域名反写。

例如:

<groupId>com.example</groupId>

如果公司域名是:

example.com

那么 groupId 通常写成:

com.example

个人项目可以写:

<groupId>com.memoryleak</groupId>

5. artifactId

artifactId 表示项目名称或者模块名称。

例如:

<artifactId>student-management-system</artifactId>

它代表当前项目叫:

student-management-system

6. version

version 表示项目版本。

例如:

<version>1.0-SNAPSHOT</version>

其中:

1.0 表示版本号
SNAPSHOT 表示快照版本,也就是开发中的版本

常见版本形式:

1.0-SNAPSHOT    开发版
1.0.0           正式版
2.1.3           正式迭代版本

7. Maven 坐标示意图

flowchart LR
    A[Maven 坐标] --> B[groupId<br/>组织或公司]
    A --> C[artifactId<br/>项目或模块名]
    A --> D[version<br/>版本号]
    B --> E[com.example]
    C --> F[demo]
    D --> G[1.0-SNAPSHOT]

七、Maven 依赖详解

1. dependencies 标签

所有依赖通常写在:

<dependencies>
    
</dependencies>

里面。

例如:

<dependencies>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.4.0</version>
    </dependency>
</dependencies>

2. dependency 标签

每一个 <dependency> 代表一个依赖。

一个完整依赖通常包含:

<dependency>
    <groupId>依赖所属组织</groupId>
    <artifactId>依赖名称</artifactId>
    <version>依赖版本</version>
    <scope>依赖作用范围</scope>
</dependency>

其中 scope 可以不写,不写时默认是 compile


八、Maven 依赖下载过程

当我们添加一个依赖后,Maven 的查找顺序大概是:

1. 先查找本地仓库
2. 如果本地仓库没有,就去远程仓库下载
3. 下载成功后保存到本地仓库
4. 当前项目使用本地仓库中的依赖

流程图如下:

flowchart TD
    A[项目 pom.xml 中声明依赖] --> B[Maven 开始解析依赖]
    B --> C{本地仓库是否存在?}
    C -- 存在 --> D[直接使用本地仓库中的 jar]
    C -- 不存在 --> E[访问远程仓库]
    E --> F{远程仓库是否存在?}
    F -- 存在 --> G[下载 jar 和 pom 文件]
    G --> H[保存到本地仓库]
    H --> D
    F -- 不存在 --> I[报错: Could not find artifact]

九、Maven 仓库

Maven 仓库用来存放 jar 包、插件、项目构件。

Maven 仓库主要分为三类:

本地仓库
中央仓库
私服仓库

1. 本地仓库

本地仓库就是你电脑上的 Maven 缓存目录。

Windows 默认位置:

C:\Users\你的用户名\.m2\repository

例如:

C:\Users\MemoryLeak\.m2\repository

Linux 或 macOS 默认位置:

~/.m2/repository

当 Maven 第一次下载某个依赖时,会把它保存到本地仓库。

以后如果其他项目也使用同一个依赖,Maven 就不用再次下载,而是直接使用本地仓库中的文件。


2. 中央仓库

中央仓库是 Maven 默认使用的公共远程仓库。

大量常见 Java 依赖都可以从中央仓库下载,例如:

Spring Boot
MyBatis
MySQL Driver
JUnit
Lombok
Jackson
Logback
Apache Commons

3. 私服仓库

私服仓库通常是公司内部搭建的 Maven 仓库。

常见工具有:

Nexus
Artifactory

公司使用私服仓库的原因:

1. 提高依赖下载速度
2. 统一管理公司内部 jar 包
3. 避免每个人都访问外网仓库
4. 控制依赖版本
5. 提高构建稳定性

4. 仓库关系图

flowchart TD
    A[Java 项目] --> B[Maven]
    B --> C[本地仓库 ~/.m2/repository]
    C --> D{依赖是否存在?}
    D -- 存在 --> E[使用本地依赖]
    D -- 不存在 --> F[远程仓库]
    F --> G[中央仓库 Maven Central]
    F --> H[公司私服 Nexus/Artifactory]
    G --> I[下载到本地仓库]
    H --> I
    I --> E

十、Maven 本地仓库目录长什么样?

比如有一个依赖:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.4.0</version>
</dependency>

它在本地仓库中大致会变成:

.m2/repository
└── com
    └── mysql
        └── mysql-connector-j
            └── 8.4.0
                ├── mysql-connector-j-8.4.0.jar
                ├── mysql-connector-j-8.4.0.pom
                └── _remote.repositories

注意:

groupId 中的点号会变成目录层级
com.mysql -> com/mysql

十一、Maven 配置文件 settings.xml

除了项目里的 pom.xml,Maven 还有一个全局或用户级配置文件:

settings.xml

常见位置:

Maven安装目录/conf/settings.xml

或者:

C:\Users\你的用户名\.m2\settings.xml

Linux/macOS:

~/.m2/settings.xml

1. settings.xml 和 pom.xml 的区别

文件 作用
pom.xml 描述当前项目的依赖、插件、构建方式
settings.xml 描述 Maven 自身配置,例如本地仓库位置、镜像、私服账号

简单说:

pom.xml 管项目
settings.xml 管 Maven 自己

2. 配置本地仓库位置

默认本地仓库在:

C:\Users\用户名\.m2\repository

如果你想改到 D 盘,可以在 settings.xml 中配置:

<settings>
    <localRepository>D:\MavenRepository</localRepository>
</settings>

这样 Maven 下载的 jar 包就会放到:

D:\MavenRepository

3. 配置国内镜像

如果下载依赖很慢,可以配置国内镜像。

示例:

<settings>
    <mirrors>
        <mirror>
            <id>aliyunmaven</id>
            <mirrorOf>central</mirrorOf>
            <name>阿里云公共仓库</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
    </mirrors>
</settings>

含义:

标签 作用
id 镜像 ID
mirrorOf 替代哪个仓库
name 镜像名称
url 镜像地址

十二、Maven 生命周期

Maven 的构建不是随便执行的,它有固定的生命周期。

Maven 内置三个生命周期:

clean
default
site

1. clean 生命周期

clean 生命周期负责清理项目。

最常见命令:

mvn clean

它会删除 target 目录。


2. default 生命周期

default 是最常用的生命周期,负责项目的主要构建流程。

常见阶段如下:

validate
compile
test
package
verify
install
deploy

解释如下:

阶段 作用
validate 验证项目是否正确
compile 编译主代码
test 运行测试代码
package 打包成 jar 或 war
verify 检查包是否有效
install 安装到本地仓库
deploy 发布到远程仓库

3. site 生命周期

site 生命周期用于生成项目站点文档。

常见命令:

mvn site

普通学习和一般业务开发中较少使用。


十三、生命周期执行顺序

Maven 生命周期有一个非常重要的特点:

执行后面的阶段时,前面的阶段会自动执行。

例如:

mvn package

并不是只执行 package。

它会先执行:

validate -> compile -> test -> package

再比如:

mvn install

会执行:

validate -> compile -> test -> package -> verify -> install

流程图如下:

flowchart LR
    A[validate] --> B[compile]
    B --> C[test]
    C --> D[package]
    D --> E[verify]
    E --> F[install]
    F --> G[deploy]

所以如果你执行:

mvn package

Maven 会从 validate 一直执行到 package

如果你执行:

mvn install

Maven 会从 validate 一直执行到 install


十四、常用 Maven 命令详解

1. mvn clean

mvn clean

作用:

删除 target 目录,清理旧的编译结果。

适用场景:

1. 项目编译异常
2. target 中存在旧文件
3. 想重新完整构建项目

2. mvn compile

mvn compile

作用:

编译 src/main/java 中的代码。

编译结果会放在:

target/classes

3. mvn test

mvn test

作用:

编译并运行 src/test/java 中的测试代码。

4. mvn package

mvn package

作用:

将项目打包成 jar 或 war。

打包结果通常在:

target/项目名-版本号.jar

例如:

target/demo-1.0-SNAPSHOT.jar

5. mvn install

mvn install

作用:

把当前项目打包,并安装到本地 Maven 仓库。

什么时候用?

当你的项目 A 需要被另一个项目 B 引用时,可以先在项目 A 中执行:

mvn install

然后项目 B 就可以通过 Maven 坐标引用项目 A。


6. mvn deploy

mvn deploy

作用:

把项目发布到远程仓库。

一般公司内部公共模块、SDK、工具包会用到。

普通初学者不常用。


7. 跳过测试打包

有时测试代码有问题,但你想先打包,可以用:

mvn package -DskipTests

这个命令会跳过测试运行,但可能仍然编译测试代码。

如果连测试代码编译也想跳过,可以用:

mvn package -Dmaven.test.skip=true

区别:

命令 作用
-DskipTests 跳过测试运行,但可能编译测试代码
-Dmaven.test.skip=true 跳过测试编译和测试运行

8. 查看依赖树

mvn dependency:tree

作用:

查看当前项目的完整依赖关系。

这个命令在排查依赖冲突时非常有用。

例如你发现项目中有多个版本的日志包,就可以通过依赖树查看是谁引入的。


9. 强制更新依赖

mvn clean package -U

-U 的作用是强制更新依赖。

适用场景:

1. SNAPSHOT 版本依赖更新了
2. 本地依赖缓存异常
3. 远程仓库依赖变动后本地没有刷新

十五、Maven 插件

Maven 的很多功能其实不是 Maven 本体直接完成的,而是通过插件完成的。

比如:

功能 插件
编译 Java 代码 maven-compiler-plugin
运行测试 maven-surefire-plugin
打包 jar maven-jar-plugin
打包 war maven-war-plugin
清理 target maven-clean-plugin
生成源码包 maven-source-plugin
Spring Boot 打包 spring-boot-maven-plugin

1. maven-compiler-plugin

这个插件用来配置 Java 编译版本。

例如:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.13.0</version>
            <configuration>
                <source>24</source>
                <target>24</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

含义:

source = 使用 Java 24 语法编译
target = 生成 Java 24 版本字节码
encoding = 使用 UTF-8 编码

也可以在 properties 中写:

<properties>
    <maven.compiler.source>24</maven.compiler.source>
    <maven.compiler.target>24</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

2. spring-boot-maven-plugin

Spring Boot 项目通常会有:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

作用:

把 Spring Boot 项目打包成可直接运行的 jar 包。

普通 jar 包可能不能直接运行,而 Spring Boot 打包后的 jar 包可以通过:

java -jar demo.jar

直接运行。


十六、Maven 生命周期、阶段、插件、目标之间的关系

这是 Maven 比较容易混乱的地方。

先看几个概念:

概念 英文 含义
生命周期 lifecycle 一套构建流程
阶段 phase 生命周期中的某一步
插件 plugin 真正执行任务的工具
目标 goal 插件中的具体任务

举例:

mvn compile

这里的 compile 是生命周期中的一个阶段。

Maven 执行到 compile 阶段时,会调用编译插件的某个目标来完成编译。

再比如:

mvn dependency:tree

这里的:

dependency = 插件
tree = 插件目标

它的意思是执行 Maven Dependency Plugin 插件中的 tree 目标,用来打印依赖树。


关系图

flowchart TD
    A[生命周期 Lifecycle] --> B[阶段 Phase]
    B --> C[插件 Plugin]
    C --> D[目标 Goal]
    D --> E[具体任务: 编译/测试/打包/清理]

十七、Maven 依赖范围 scope

Maven 依赖中有一个重要配置:

<scope>...</scope>

它表示依赖在什么时候生效。

常见 scope 有:

compile
provided
runtime
test
system
import

1. compile

默认值。

如果不写 scope,默认就是 compile。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
</dependency>

等价于:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version>
    <scope>compile</scope>
</dependency>

特点:

编译时需要
运行时需要
测试时需要
会被打包传播

常见依赖:

工具类库
业务代码依赖库
Spring 核心库

2. provided

provided 表示编译时需要,但运行时由外部环境提供。

典型例子:

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0</version>
    <scope>provided</scope>
</dependency>

含义:

编译代码时需要 Servlet API
但真正运行时 Tomcat 容器会提供它
所以打包时不需要把它打进去

常见场景:

Servlet API
某些应用服务器提供的依赖

3. runtime

runtime 表示编译时不需要,运行时需要。

典型例子:

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.4.0</version>
    <scope>runtime</scope>
</dependency>

例如 JDBC 编程时,代码里主要依赖 JDBC 接口,而 MySQL 驱动在运行时才真正发挥作用。


4. test

test 表示只在测试时使用。

典型例子:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
</dependency>

特点:

主代码不能使用
测试代码可以使用
不会被打包到正式项目中

5. system

system 表示手动指定本地 jar 路径。

不推荐使用。

示例:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>local-lib</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/libs/local-lib.jar</systemPath>
</dependency>

缺点:

依赖路径写死
不利于团队协作
不利于跨平台
不利于构建稳定

一般不建议这样做。


6. scope 总结表

scope 编译主代码 运行主程序 编译测试 运行测试 是否打包
compile
provided
runtime
test
system 不推荐

十八、Maven 依赖传递

Maven 有一个非常重要的功能:

依赖可以传递。

什么意思?

假设:

你的项目 A 依赖 B
B 又依赖 C

那么 Maven 会自动把 C 也引入进来。

也就是:

A -> B -> C

只要你引入 B,C 也会被 Maven 自动引入。

流程图如下:

flowchart LR
    A[项目 A] --> B[依赖 B]
    B --> C[依赖 C]
    C --> D[依赖 D]

这种间接依赖叫做:

传递依赖

十九、依赖冲突

依赖传递虽然方便,但也会带来依赖冲突问题。

例如:

项目 A 依赖 B 和 C
B 依赖 logback 1.2.0
C 依赖 logback 1.4.0

那么项目里到底使用哪个版本?

Maven 有自己的依赖调解规则。

常见规则:

1. 路径最近者优先
2. 路径相同则先声明者优先

1. 路径最近者优先

例如:

项目 A -> B -> D 1.0
项目 A -> C -> E -> D 2.0

D 1.0 距离项目 A 更近,所以 Maven 可能选择 D 1.0。

图示:

flowchart TD
    A[项目 A] --> B[依赖 B]
    A --> C[依赖 C]
    B --> D1[D 1.0<br/>距离更近]
    C --> E[依赖 E]
    E --> D2[D 2.0<br/>距离更远]

2. 路径相同则先声明者优先

如果两个版本路径深度一样,那么谁在 pom.xml 中先声明,谁优先。


3. 查看依赖冲突

可以使用:

mvn dependency:tree

也可以输出到文件:

mvn dependency:tree -DoutputFile=dependency-tree.txt

4. 排除传递依赖

如果你不想引入某个传递依赖,可以使用 exclusions

例如:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>some-library</artifactId>
    <version>1.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.example</groupId>
            <artifactId>bad-library</artifactId>
        </exclusion>
    </exclusions>
</dependency>

含义:

引入 some-library
但是排除它传递进来的 bad-library

二十、dependencyManagement

dependencyManagement 是 Maven 中非常重要但容易误解的标签。

它的作用是:

统一管理依赖版本,但不会真正引入依赖。

例如父工程中写:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.4.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

这并不代表当前项目已经引入了 MySQL 驱动。

子模块真正使用时还要写:

<dependencies>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>
</dependencies>

注意这里可以不写 version,因为版本已经由父工程统一管理。


dependencyManagement 和 dependencies 的区别

标签 作用 是否真正引入依赖
dependencies 声明项目实际使用的依赖
dependencyManagement 管理依赖版本

简单记忆:

dependencies = 真正买东西
dependencyManagement = 只写购物清单价格标准

二十一、Maven 父工程

在大型项目中,通常会有父工程。

父工程常用来统一管理:

1. JDK 版本
2. 编码格式
3. Spring Boot 版本
4. 第三方依赖版本
5. Maven 插件版本
6. 子模块列表

父工程通常是:

<packaging>pom</packaging>

示例:

<project>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my-parent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>pom</packaging>

    <modules>
        <module>user-service</module>
        <module>order-service</module>
    </modules>
</project>

二十二、Maven 多模块项目

多模块项目就是一个父工程下面包含多个子模块。

例如:

my-system
├── pom.xml
├── common
│   └── pom.xml
├── user-service
│   └── pom.xml
└── order-service
    └── pom.xml

含义:

模块 作用
my-system 父工程,统一管理版本和模块
common 公共工具模块
user-service 用户模块
order-service 订单模块

多模块关系图

flowchart TD
    A[父工程 my-system] --> B[common 公共模块]
    A --> C[user-service 用户模块]
    A --> D[order-service 订单模块]
    C --> B
    D --> B

如果 user-service 想使用 common,可以在 user-service/pom.xml 中写:

<dependency>
    <groupId>com.example</groupId>
    <artifactId>common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

二十三、packaging 打包类型

Maven 中可以通过 packaging 指定打包方式。

常见类型:

packaging 含义
jar 普通 Java 项目,打成 jar 包
war Java Web 项目,打成 war 包
pom 父工程,不打包代码,只管理模块和配置

如果不写,默认是:

<packaging>jar</packaging>

父工程通常写:

<packaging>pom</packaging>

Web 项目可能写:

<packaging>war</packaging>

二十四、Maven 和 Spring Boot

Spring Boot 项目通常使用 Maven 管理依赖。

一个典型 Spring Boot 项目 pom.xml 如下:

<project>
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>springboot-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <!-- Spring Web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MySQL 驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Spring Boot 打包插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

二十五、starter 是什么?

Spring Boot 里经常看到:

<artifactId>spring-boot-starter-web</artifactId>

这里的 starter 可以理解成:

一组依赖的集合。

比如 spring-boot-starter-web 会帮你引入开发 Web 所需要的一组依赖。

你不需要手动一个个引入:

Spring MVC
Tomcat
Jackson
Validation
日志组件

Spring Boot starter 帮你打包管理好了。


二十六、Maven 和 JDK 版本

Maven 构建 Java 项目时,需要调用 JDK。

也就是说:

Maven 自己不编译 Java
真正编译 Java 的是 JDK 中的 javac
Maven 只是组织构建流程

因此 Maven 使用哪个 JDK 非常重要。

比如你的 pom.xml 写:

<properties>
    <maven.compiler.source>24</maven.compiler.source>
    <maven.compiler.target>24</maven.compiler.target>
</properties>

意思是:

使用 Java 24 语法编译
生成 Java 24 字节码

如果 Maven 实际使用的是 JDK 17,就可能报错。

常见错误类似:

invalid target release: 24

原因就是:

Maven 当前使用的 JDK 版本太低,不支持 target 24

二十七、IDEA 中 Maven 和 JDK 的关系

在 IDEA 中,至少有几个位置和 JDK 有关:

1. Project SDK
2. Module SDK
3. Maven Runner JRE
4. pom.xml 中的 source/target

它们最好保持一致。

例如你项目使用 Java 24,那么建议:

Project SDK = JDK 24
Module SDK = JDK 24
Maven Runner JRE = JDK 24
pom.xml source/target = 24

否则就容易出现:

IDEA 能运行
Maven 打包失败

或者:

Maven 能编译
IDEA 代码提示异常

二十八、Maven Wrapper

Maven Wrapper 是什么?

它可以理解成:

项目自带的 Maven 启动器。

普通 Maven 命令:

mvn clean package

使用 Maven Wrapper:

Windows:

mvnw.cmd clean package

Linux/macOS:

./mvnw clean package

Maven Wrapper 有什么用?

Maven Wrapper 的好处:

1. 不要求使用者提前安装 Maven
2. 可以让团队使用同一个 Maven 版本
3. 避免“我电脑能跑,你电脑不能跑”
4. 适合开源项目和团队项目

但是要注意:

Maven Wrapper 能帮你管理 Maven 版本,但不能替你安装 JDK。

也就是说,你仍然需要正确安装 JDK。


Maven Wrapper 项目结构

使用 Maven Wrapper 的项目通常会多出这些文件:

my-project
├── mvnw
├── mvnw.cmd
├── .mvn
│   └── wrapper
│       └── maven-wrapper.properties
├── pom.xml
└── src

其中:

文件 作用
mvnw Linux/macOS 下使用的 Maven Wrapper 脚本
mvnw.cmd Windows 下使用的 Maven Wrapper 脚本
.mvn/wrapper/maven-wrapper.properties 指定 Maven Wrapper 下载哪个 Maven 版本

二十九、Maven 和 Gradle 的区别

Java 项目常见构建工具有:

Maven
Gradle

对比如下:

对比项 Maven Gradle
配置文件 XML Groovy/Kotlin DSL
学习难度 较低 较高
规则 约定强、规范统一 灵活度高
构建速度 一般 通常更快
常见场景 Java 后端、传统企业项目 Android、大型复杂项目
初学推荐 推荐 后期再学

对于 Java 后端初学者,建议先掌握 Maven。

因为 Spring Boot、MyBatis、企业后端项目中 Maven 非常常见。


三十、完整 pom.xml 示例:普通 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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- POM 模型版本,固定写 4.0.0 -->
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目坐标 -->
    <groupId>com.example</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 打包方式,默认 jar -->
    <packaging>jar</packaging>

    <!-- 项目属性 -->
    <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>
        <!-- Apache Commons Lang 工具包 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>

        <!-- JUnit 测试框架 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建配置 -->
    <build>
        <plugins>
            <!-- Java 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

三十一、完整 pom.xml 示例:Spring Boot 项目

<?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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <!-- Spring Boot 父工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
        <relativePath/>
    </parent>

    <!-- 当前项目坐标 -->
    <groupId>com.example</groupId>
    <artifactId>springboot-maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 项目属性 -->
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- 依赖 -->
    <dependencies>
        <!-- Web 开发依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- MySQL 驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- Lombok,简化实体类代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建插件 -->
    <build>
        <plugins>
            <!-- Spring Boot 打包插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

三十二、常见 Maven 报错与解决方法

1. Could not find artifact

错误示例:

Could not find artifact com.example:xxx:jar:1.0

原因可能是:

1. 依赖坐标写错了
2. 版本号不存在
3. 远程仓库没有这个依赖
4. 网络无法访问 Maven 仓库
5. 公司私服没有配置

解决方法:

1. 检查 groupId、artifactId、version 是否正确
2. 检查网络
3. 配置国内镜像
4. 如果是本地模块,先执行 mvn install

2. invalid target release

错误示例:

invalid target release: 24

原因:

pom.xml 中配置了 Java 24
但 Maven 实际使用的 JDK 版本低于 24

解决:

1. 安装 JDK 24
2. 配置 JAVA_HOME 指向 JDK 24
3. IDEA 中 Maven Runner JRE 选择 JDK 24
4. 确认命令行 java -version 和 mvn -version

检查命令:

java -version
mvn -version

重点看:

mvn -version 中显示的 Java version

3. Dependency not found

IDEA 中依赖标红,通常原因:

1. Maven 没刷新
2. 依赖没下载成功
3. 本地仓库缓存损坏
4. settings.xml 配置错误
5. 网络问题

解决:

1. 点击 IDEA Maven 面板 Reload All Maven Projects
2. 执行 mvn clean package -U
3. 删除本地仓库中对应依赖目录后重新下载
4. 检查 settings.xml

4. 编码乱码

如果项目中出现中文乱码,可以在 pom.xml 中配置:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

同时 IDEA 中也建议设置:

File Encoding = UTF-8

5. 程序包 xxx 不存在

错误示例:

程序包 org.springframework.web.bind.annotation 不存在

原因:

1. 依赖没有引入
2. Maven 没刷新
3. 依赖下载失败
4. 代码 import 错误

解决:

1. 检查 pom.xml 是否添加相关依赖
2. 刷新 Maven
3. 执行 mvn clean compile
4. 查看 External Libraries 是否存在对应 jar

三十三、Maven 学习路线

如果你是 Java 初学者,建议按这个顺序学习 Maven:

第一阶段:理解 Maven 是什么
第二阶段:掌握 pom.xml 基本结构
第三阶段:会添加 dependency
第四阶段:理解本地仓库和远程仓库
第五阶段:会使用常用命令 clean/compile/package/install
第六阶段:理解生命周期
第七阶段:理解 scope
第八阶段:会查看 dependency:tree
第九阶段:理解 dependencyManagement
第十阶段:能看懂 Spring Boot 项目的 pom.xml
第十一阶段:理解父工程和多模块
第十二阶段:掌握 Maven Wrapper

三十四、Maven 学习路线图

flowchart TD
    A[认识 Maven] --> B[理解 pom.xml]
    B --> C[掌握 GAV 坐标]
    C --> D[添加 dependencies]
    D --> E[理解本地仓库和远程仓库]
    E --> F[掌握常用 Maven 命令]
    F --> G[理解生命周期]
    G --> H[理解插件和目标]
    H --> I[掌握 scope]
    I --> J[排查依赖冲突]
    J --> K[理解 dependencyManagement]
    K --> L[掌握父工程和多模块]
    L --> M[理解 Spring Boot Maven 项目]
    M --> N[掌握 Maven Wrapper]

三十五、Maven 面试常见问题

1. Maven 是什么?

Maven 是一个项目管理和构建工具,主要用于 Java 项目。它可以通过 pom.xml 管理项目依赖、统一项目结构、执行编译、测试、打包、安装、部署等构建流程。


2. Maven 的核心作用是什么?

主要有三个:

1. 依赖管理
2. 项目构建
3. 项目信息管理

具体包括:

下载第三方 jar 包
管理依赖版本
统一项目目录结构
编译代码
运行测试
打包项目
发布项目

3. pom.xml 是什么?

pom.xml 是 Maven 项目的核心配置文件。

它用于描述:

项目坐标
项目依赖
构建插件
打包方式
父工程
子模块
仓库配置
编译版本

4. Maven 坐标是什么?

Maven 坐标由三部分组成:

groupId
artifactId
version

例如:

<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>

它们可以唯一定位一个 Maven 构件。


5. Maven 生命周期有哪些?

Maven 内置三个生命周期:

clean
default
site

其中 default 生命周期最常用,包含:

validate
compile
test
package
verify
install
deploy

6. mvn package 和 mvn install 的区别是什么?

mvn package

将项目打包,生成 jar 或 war,结果在 target 目录下。

mvn install

不仅会打包,还会把打包结果安装到本地 Maven 仓库。

也就是说:

install 包含 package 的过程。

7. dependencyManagement 和 dependencies 的区别是什么?

dependencies

真正引入依赖。

dependencyManagement

只管理依赖版本,不真正引入依赖。

子模块如果要使用某个依赖,仍然需要在 dependencies 中声明。


8. Maven 如何解决依赖冲突?

Maven 常见依赖调解规则:

1. 路径最近者优先
2. 路径相同则先声明者优先

可以通过:

mvn dependency:tree

查看依赖树,分析冲突来源。


9. Maven scope 有哪些?

常见 scope:

compile
provided
runtime
test
system
import

最常用的是:

scope 含义
compile 默认,编译和运行都需要
provided 编译需要,运行环境提供
runtime 编译不需要,运行需要
test 只在测试时使用

10. Maven Wrapper 是什么?

Maven Wrapper 是项目自带的 Maven 启动脚本。

它可以让项目使用指定版本的 Maven,而不要求开发者提前全局安装 Maven。

Windows 下使用:

mvnw.cmd clean package

Linux/macOS 下使用:

./mvnw clean package

三十六、适合初学者的 Maven 实战步骤

第一步:创建 Maven 项目

项目结构:

maven-demo
├── pom.xml
└── src
    └── main
        └── java
            └── com
                └── example
                    └── Main.java

第二步:编写 Main.java

package com.example;

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello 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
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>maven-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

第四步:执行编译

mvn compile

成功后会生成:

target/classes/com/example/Main.class

第五步:执行打包

mvn package

成功后会生成:

target/maven-demo-1.0-SNAPSHOT.jar

三十七、Maven 最重要的几个记忆点

初学者只要先记住这些:

1. Maven 是 Java 项目的构建和依赖管理工具。
2. Maven 项目的核心文件是 pom.xml。
3. Maven 通过 groupId、artifactId、version 定位依赖。
4. Maven 会先查本地仓库,没有再去远程仓库下载。
5. Maven 默认本地仓库在 ~/.m2/repository。
6. Maven 生命周期包括 clean、default、site。
7. mvn package 会打包项目。
8. mvn install 会把项目安装到本地仓库。
9. dependencies 是真正引入依赖。
10. dependencyManagement 只是统一管理版本。
11. Maven 插件负责真正执行编译、测试、打包等任务。
12. Spring Boot 项目通常使用 Maven 管理依赖和打包。

三十八、总结

Maven 是 Java 开发中非常基础也非常重要的工具。

对于初学者来说,不要一开始就陷入复杂配置,而应该先掌握它的主线:

pom.xml 写项目配置
dependencies 管理依赖
repository 存放依赖
lifecycle 组织构建流程
plugin 执行具体任务
package/install 完成打包和安装

只要理解了这条主线,再去看 Spring Boot 项目的 pom.xml,就不会觉得它是一堆看不懂的 XML 标签。

最后用一句话总结 Maven:

Maven 就是 Java 项目的自动化管家:它按照 pom.xml 这份说明书,帮我们下载依赖、管理版本、编译代码、运行测试、打包项目,让 Java 项目开发更加规范、稳定、可复现。

更多推荐