本笔记聚焦 Maven 核心基础概念、常用操作和最佳实践,覆盖 Java 开发中 Maven 的全量基础使用场景,帮助零基础开发者快速上手并掌握 Maven 的核心能力。
一、Maven 核心思想与概述
1.1 什么是 Maven?
Maven 是 Apache 旗下的项目构建与依赖管理工具,是 Java 生态中最主流的项目管理标准工具。其核心设计理念有两点:
- 约定优于配置(Convention Over Configuration):Maven 预设了标准化的项目结构、构建流程,开发者无需手动配置每一个环节,大幅减少配置工作量与学习成本。
- 项目对象模型(Project Object Model,POM) :将项目的所有信息、配置集中在
pom.xml文件中,通过该文件统一管理项目的全生命周期。
1.2 为什么需要 Maven?
- 解决依赖管理核心痛点:彻底解决手动导入 Jar 包的繁琐操作,以及依赖版本冲突、依赖缺失、Jar 包来源不规范等问题,实现依赖的自动化管理。
- 标准化项目全流程:提供统一的项目结构、标准化的构建流程(编译、测试、打包、部署),所有 Maven 项目的结构与构建逻辑一致,避免了 "本地可运行、服务器无法运行" 的环境差异问题。
- 提升团队协作效率:团队成员使用统一的依赖配置、构建标准,降低协作成本,同时便于项目的版本管理与持续集成落地。
二、Maven 核心概念与安装
2.1 核心概念
- POM(Project Object Model) :Maven 的核心载体,对应项目根目录下的
pom.xml文件。项目的所有配置(坐标、依赖、插件、构建规则等)都在该文件中定义,Maven 执行任务时会读取该文件完成对应操作。 - 坐标(Coordinates) :Maven 中唯一标识一个项目 / 依赖组件 的核心标识,由三个必填字段组成,是依赖管理的基础:
groupId:组织标识,通常为公司 / 组织域名反写(如org.apache.commons);artifactId:项目 / 组件标识,同一groupId下的唯一项目名;version:版本号,标识组件的迭代版本。
- 仓库(Repository) :Maven 存放所有 Jar 包 / 组件的统一位置,分为三类:
- 本地仓库 :开发者本地电脑的目录,默认路径为
~/.m2/repository(Windows 为C:\Users\用户名\.m2\repository)。Maven 会优先从本地仓库查找依赖,找不到再去远程仓库下载。 - 远程仓库 / 中央仓库(Maven Central) :Maven 官方全球公共仓库,由 Sonatype 负责管理近 20 年,是全球最大的 Java 开源组件仓库,2025 年全量公共仓库的开源组件下载量达 9.8 万亿次,官方搜索地址为https://search.maven.org/。
- 私服:企业 / 团队内部搭建的私有仓库(常用工具为 Sonatype Nexus、JFrog Artifactory),用于存放内部私有组件,同时可作为中央仓库的镜像,提升依赖下载速度。
- 本地仓库 :开发者本地电脑的目录,默认路径为
- 依赖(Dependencies) :项目运行所需的外部 Jar 包 / 组件,在
pom.xml中通过<dependencies>标签声明,Maven 会自动根据坐标下载对应依赖及其传递依赖。 - 生命周期(Lifecycle)& 阶段(Phase) :Maven 预设的一套标准化项目构建流程,每个生命周期由一系列有序的阶段组成。执行某个阶段时,会自动按顺序执行其之前的所有前置阶段,核心阶段包括
clean、compile、test、package、install、deploy等。 - 插件(Plugins) :Maven 功能的实际实现者,生命周期的每个阶段都绑定了插件的具体目标(Goal),插件才是真正执行构建任务的载体,例如
compile阶段绑定的是maven-compiler-plugin插件。
2.2 安装与配置
- 前置条件 :Maven 基于 Java 运行,需先安装 JDK(1.8 及以上版本),并配置好
JAVA_HOME环境变量。 - 下载安装 :从 Apache Maven 官网下载对应系统的二进制压缩包(
bin.zip/bin.tar.gz),解压到本地无中文、无空格的目录(如 Windows:D:\apache-maven-3.9.6,Linux/Mac:/usr/local/apache-maven-3.9.6)。 - 配置环境变量 :
- 新建系统变量
M2_HOME,值为 Maven 的解压根目录; - 编辑系统变量
Path,新增%M2_HOME%\bin(Windows)或$M2_HOME/bin(Linux/Mac)。
- 新建系统变量
- 验证安装 :打开命令行终端,执行
mvn -v,若输出 Maven 版本、JDK 版本等信息,即为安装成功。 - 可选核心配置(settings.xml) :
settings.xml是 Maven 的全局配置文件,分为两个位置:全局配置(Maven 安装目录 /conf/settings.xml)、用户级配置(~/.m2/settings.xml,优先级更高),常用配置包括修改本地仓库路径、配置国内镜像仓库、私服地址等。
三、Maven 项目结构与 pom.xml
3.1 标准的项目目录结构(约定优于配置的核心体现)
Maven 严格约定了项目目录结构,无需额外配置即可自动识别目录用途,违背该结构会导致 Maven 无法正常识别源码,所有 Maven 项目均推荐使用该标准结构:
plaintext
project-root # 项目根目录
├── src
│ ├── main
│ │ ├── java # 主Java源代码,编译后输出到target/classes
│ │ └── resources # 主资源文件(配置文件、静态资源等),编译后复制到target/classes
│ └── test
│ ├── java # 测试代码目录(JUnit等测试代码)
│ └── resources # 测试专用资源文件
├── target # 编译、打包的输出目录,自动生成,执行clean会删除
└── pom.xml # 项目核心配置文件,必须存在
3.2 pom.xml 基础解析
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- POM模型版本,Maven3固定为4.0.0 -->
<modelVersion>4.0.0</modelVersion>
<!-- 项目核心坐标,必须配置 -->
<groupId>com.example</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 打包类型,默认是jar,可选war、pom等 -->
<packaging>jar</packaging>
<!-- 属性定义:统一管理变量,如JDK版本、依赖版本,便于维护 -->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.13.2</junit.version>
</properties>
<!-- 依赖管理:声明项目需要的所有外部依赖 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 构建配置:管理插件、编译输出等构建相关配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
核心标签说明:
- 项目坐标 :
<groupId>、<artifactId>、<version>为必填项,唯一标识当前项目,也是其他项目依赖本项目的依据。 - 打包类型
<packaging>:定义项目打包方式,默认值jar(Java 普通项目);war用于 Java Web 项目;pom用于父项目 / 聚合项目,仅做依赖和模块管理,不打包业务代码。 - 属性定义
<properties>:用于定义全局变量,格式为<变量名>值</变量名>,可通过${变量名}引用。最常用于统一管理 JDK 版本、依赖版本、编码格式,避免重复配置,便于版本统一升级。 - 依赖管理
<dependencies>:项目核心依赖配置,可包含多个<dependency>标签,每个标签对应一个依赖组件。 - 构建配置
<build>:配置项目的构建过程,核心为<plugins>插件配置,可自定义插件参数、绑定的生命周期阶段等。
四、依赖管理(核心重点)
4.1 依赖坐标与引入
- 依赖声明格式 :在
pom.xml的<dependencies>标签内,添加<dependency>标签并填入依赖的 gav 坐标即可,示例如下:
xml
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
- 依赖搜索方式 :官方搜索地址为https://search.maven.org/,可搜索所有发布到 Maven 中央仓库的组件,步骤如下:
- 打开站点,在搜索框输入组件名(如 commons-lang3),点击搜索;
- 在结果中找到对应的 groupId 和 artifactId,选择需要的版本;
- 站点会自动生成对应的
<dependency>代码,直接复制粘贴到 pom.xml 的<dependencies>中即可。
4.2 依赖范围(Scope)
依赖范围用于控制依赖在编译、测试、运行三个生命周期阶段的有效性,同时影响依赖的传递性,常用 scope 如下:
表格
| Scope 范围 | 编译有效 | 测试有效 | 运行有效 | 传递性 | 典型使用场景 |
|---|---|---|---|---|---|
| compile(默认) | ✅ | ✅ | ✅ | 是 | 绝大多数业务依赖包,如 commons-lang3 |
| provided | ✅ | ✅ | ❌ | 否 | 运行时由容器提供的包,如 Servlet API、Tomcat 相关依赖 |
| runtime | ❌ | ✅ | ✅ | 是 | 编译时不需要、仅运行时需要的包,如 JDBC 驱动 |
| test | ❌ | ✅ | ❌ | 否 | 仅测试阶段使用的包,如 JUnit、Mockito 测试框架 |
| system | ✅ | ✅ | ❌ | 否 | 需通过<systemPath>指定本地 Jar 包路径,不推荐使用 |
4.3 依赖传递与冲突解决
-
传递性依赖Maven 依赖具备传递性:若 A 项目依赖 B,B 项目依赖 C,则 A 项目会自动依赖 C,无需在 A 的 pom 中手动声明 C 的依赖,Maven 会自动下载并引入所有层级的传递依赖,大幅简化依赖管理。
-
依赖冲突与解决原则依赖冲突的产生:当项目中多个依赖传递引入了同一个 Jar 包的不同版本,Maven 会通过以下两个固定原则决定最终使用的版本,优先级从高到低:
- 最短路径优先:依赖的层级越浅、路径越短,优先级越高。示例:A→B→C→D (1.0),A→E→D (2.0),D (2.0) 路径长度为 2,短于 D (1.0) 的 3 级路径,最终使用 D (2.0) 版本。
- 先声明优先:当路径长度相同时,在 pom.xml 中先声明的依赖,优先级更高。示例:A→B→D (1.0),A→E→D (2.0),两个路径长度均为 2,pom 中先声明的依赖对应的 D 版本会被使用。
- 冲突与传递的手动控制
-
排除依赖
<exclusions>:当传递的依赖不需要或存在版本冲突时,可手动排除指定的传递依赖,示例如下:xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.30</version> <exclusions> <!-- 排除指定传递依赖,仅需groupId和artifactId,无需version --> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> -
可选依赖
<optional>true</optional>:声明依赖为可选,该依赖不会传递给依赖当前项目的其他项目,示例如下:xml
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson2</artifactId> <version>2.0.48</version> <optional>true</optional> </dependency>
五、生命周期与常用命令
5.1 三大生命周期(相互独立)
Maven 有三套相互独立、互不影响的生命周期,每个生命周期包含多个有序的阶段(Phase),执行某个阶段时,会按顺序执行该生命周期中该阶段之前的所有前置阶段。
-
clean 生命周期:负责清理项目,核心是删除编译打包生成的 target 目录,核心阶段为:
- pre-clean:清理前的准备工作
- clean:执行清理,删除 target 目录(日常最常用)
- post-clean:清理后的收尾工作
-
default 生命周期(核心):Maven 最核心的生命周期,负责项目的编译、测试、打包、安装、部署全流程,核心阶段按执行顺序如下:
- validate:验证项目结构、pom 配置是否正确
- compile:编译项目的主源代码,生成 class 文件到 target/classes
- test:执行单元测试,不会打包和部署
- package:将编译后的代码打包成对应格式(jar/war 等),生成到 target 目录
- verify:验证打包结果是否有效、符合标准
- install:将打包好的组件安装到本地 Maven 仓库,供本地其他项目依赖使用
- deploy:将打包好的组件部署到远程仓库(私服 / 中央仓库),供团队成员使用
关键特性:执行后面的阶段,会自动执行前面的所有阶段。例如执行
mvn install,会自动按顺序执行 validate→compile→test→package→verify→install。 -
site 生命周期:负责生成项目的站点文档、报告,日常开发中使用较少,核心阶段为 site(生成站点文档)、site-deploy(部署站点文档)。
5.2 常用命令行指令
Maven 命令格式为mvn [阶段名/插件目标] [参数],日常开发最常用的命令如下:
表格
| 命令 | 核心作用 |
|---|---|
mvn clean |
清理项目,删除 target 目录 |
mvn compile |
编译主源代码 |
mvn test |
执行所有单元测试 |
mvn package |
项目打包,生成 jar/war 包到 target 目录 |
mvn install |
打包并安装到本地仓库,供本地其他项目使用 |
mvn deploy |
打包并部署到远程仓库 |
常用组合命令与参数:
mvn clean package:组合命令,先清理项目,再执行打包,避免旧编译缓存影响打包结果,日常打包最常用。mvn clean install -DskipTests:清理、编译、打包、安装到本地仓库,跳过测试执行(仍编译测试代码)。mvn clean install -Dmaven.test.skip=true:完全跳过测试的编译与执行,构建速度更快。
六、插件(Plugins)基础
6.1 插件与目标(Goal)
Maven 的设计核心是内核仅负责生命周期的调度,所有具体的业务功能都由插件实现。
- 插件(Plugin):Maven 功能的实现载体,每个插件都是一个 Jar 包,提供一系列相关功能。
- 目标(Goal):插件的最小执行单元,一个插件包含多个目标,每个目标对应一个具体任务。
- 生命周期与插件的绑定 :生命周期的每个阶段,都会绑定一个或多个插件的目标,执行生命周期阶段,本质是执行绑定的插件目标。例如
compile阶段默认绑定maven-compiler-plugin的compile目标。
6.2 常用内置插件
Maven 内置了多个核心插件,无需额外声明即可使用,也可手动配置参数自定义执行行为,最常用的两个插件如下:
-
maven-compiler-plugin:Java 代码编译插件作用:负责编译 Java 源代码,配置项目的 JDK 编译版本、编码格式等,是最常用的插件,配置示例如下:
xml
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <!-- 源代码使用的JDK版本 --> <source>8</source> <!-- 字节码兼容的JDK版本 --> <target>8</target> <!-- 代码编码格式 --> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> -
maven-surefire-plugin:测试执行插件作用:负责执行单元测试,配置测试框架、跳过测试、指定执行的测试用例等,常用配置示例如下:
xml
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.5</version> <configuration> <!-- 跳过所有测试 --> <skipTests>true</skipTests> </configuration> </plugin>
七、多模块项目(Maven Multi-Module)基础概念
7.1 为什么需要多模块?
当项目规模扩大,单项目结构会导致代码耦合度高、难以维护、复用性差。多模块项目将大项目按功能 / 业务边界拆分为多个子模块,每个子模块独立开发、管理,核心优势如下:
- 代码解耦,职责分离,每个模块仅负责对应功能,便于维护与迭代;
- 模块复用,公共模块可被多个业务模块依赖,避免重复代码;
- 便于团队协作,不同团队可负责不同模块,互不干扰。
7.2 基本结构
Maven 多模块项目采用聚合 + 继承的设计,核心分为父模块和子模块:
-
父模块(聚合项目):
- 打包类型
<packaging>必须为pom,不存放业务代码,仅负责管理子模块、统一管理公共依赖和插件配置。 - 通过
<modules>标签声明所有子模块,在父模块执行 mvn 命令,会自动对所有子模块执行对应命令。 - 子模块可继承父模块的 pom 配置,统一管理依赖版本、插件配置,避免重复配置。
- 打包类型
-
子模块:
- 每个子模块都是独立的 Maven 项目,有自己的 pom.xml,继承父模块的配置。
- 子模块之间可相互依赖,实现功能调用。
标准多模块项目结构:
plaintext
parent-project # 父项目根目录
├── module-common # 公共工具模块
│ ├── src
│ └── pom.xml
├── module-dao # 数据访问模块
│ ├── src
│ └── pom.xml
├── module-service # 业务服务模块
│ ├── src
│ └── pom.xml
├── module-web # web接口模块
│ ├── src
│ └── pom.xml
└── pom.xml # 父项目pom.xml,packaging=pom
父模块 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.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父项目打包类型必须是pom -->
<packaging>pom</packaging>
<!-- 声明所有子模块 -->
<modules>
<module>module-common</module>
<module>module-dao</module>
<module>module-service</module>
<module>module-web</module>
</modules>
<!-- 统一管理属性 -->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.3.30</spring.version>
<mybatis.version>3.5.15</mybatis.version>
</properties>
<!-- 依赖管理:统一管理所有依赖的版本,子模块继承后无需写version -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 统一管理插件,所有子模块都会继承 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>8</source>
<target>8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
子模块 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">
<parent>
<!-- 继承父模块的坐标 -->
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父模块pom.xml的相对路径 -->
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 子模块artifactId,groupId和version默认继承父模块,无需重复写 -->
<artifactId>module-service</artifactId>
<!-- 依赖声明:继承父模块的dependencyManagement,无需写version -->
<dependencies>
<!-- 依赖本项目的其他子模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>module-dao</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 继承父模块版本的公共依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
</project>
核心补充:
<dependencyManagement>:父模块中用于统一管理依赖版本,不会直接引入依赖,子模块继承后声明依赖时无需写 version,实现全项目依赖版本的统一。<pluginManagement>:与 dependencyManagement 类似,父模块中统一管理插件的版本和配置,子模块继承后可直接使用,无需重复配置。
八、实用技巧与问题排查
8.1 配置国内镜像
Maven 默认中央仓库服务器在国外,国内下载依赖速度较慢,推荐配置阿里云 Maven 镜像,配置方式为:修改 settings.xml(推荐用户级~/.m2/settings.xml),在<mirrors>标签中添加如下配置:
xml
<mirrors>
<mirror>
<id>aliyunmaven</id>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
8.2 依赖冲突排查
当项目出现ClassNotFoundException、NoSuchMethodError等异常时,大概率是依赖版本冲突导致,可通过依赖树命令快速定位问题:
bash
运行
# 查看项目完整依赖树,展示所有依赖及其传递依赖、版本信息
mvn dependency:tree
# 将依赖树输出到文件,便于查看
mvn dependency:tree > dependency-tree.txt
# 筛选查看指定依赖的引入情况
mvn dependency:tree -Dincludes=commons-logging
通过依赖树可清晰看到依赖的引入路径、版本、是否被排除,快速定位冲突来源,通过<exclusions>排除不需要的版本即可解决冲突。
8.3 跳过测试的几种方式
日常打包、部署时,为提升构建速度,常需要跳过单元测试,Maven 提供两种常用方式:
-
命令行参数方式(临时生效,推荐)
-DskipTests:跳过测试执行,仍编译测试代码,保证测试代码语法正确,示例:mvn clean install -DskipTests-Dmaven.test.skip=true:完全跳过测试的编译与执行,构建速度更快,示例:mvn clean package -Dmaven.test.skip=true
-
pom.xml 配置方式(永久生效) 在 pom.xml 中配置 maven-surefire-plugin,设置
skipTests=true,所有构建都会跳过测试,配置示例见第六章插件配置。