一、Maven简介
Maven概述
Maven 是一个 项目构建与依赖管理工具 ,由 Apache 软件基金会开发。
它最常用于 Java 项目的构建、依赖管理、项目管理与发布。
-
依赖管理工具
-
构建工具
Maven 的核心理念
Maven 有两个最重要的概念:
- POM(Project Object Model,项目对象模型)
每个 Maven 项目都有一个pom.xml
文件,用来描述项目的结构、依赖、构建方式。 - 仓库(Repository)
存放项目依赖的 jar 包(例如 Spring、MyBatis 的 jar)。
Maven 会自动从远程仓库下载依赖并缓存到本地仓库。
Maven 的作用
分类 | 具体功能 | 说明 |
---|---|---|
依赖管理 | 自动下载、更新 jar 包 | 不需要手动下载依赖,只需声明依赖坐标 |
项目构建 | 一键编译、测试、打包、部署 | mvn clean package 就能生成可运行文件 |
项目标准化 | 统一项目结构与目录规范 | 所有 Maven 项目结构一致,便于协作 |
生命周期管理 | 控制项目从构建到发布的整个流程 | compile → test → package → install → deploy |
多模块项目管理 | 管理大型项目的多个子模块 | 父 POM 统一依赖版本、配置插件 |
插件扩展 | 通过插件扩展功能 | 比如编译、测试、生成文档、代码检查等 |
仓库管理 | 支持本地仓库、远程仓库、私服 | 方便团队共享依赖和发布包 |
工作原理模型图

二、Maven安装和配置
安装 Maven
下载 Maven
官方下载地址:
选择版本:
建议使用 Maven 3.9.x(如 3.9.9),兼容性强、性能稳定。
下载 .zip
(Windows)或 .tar.gz
(Linux / macOS)包。
解压安装
-
将下载的压缩包解压到任意目录,比如:
D:\Software\apache-maven-3.9.9
-
解压后主要目录结构如下:
apache-maven-3.9.9 ├── bin # Maven 命令文件 (mvn.cmd / mvn) ├── conf # 配置文件(settings.xml) ├── lib # 核心类库 └── LICENSE、NOTICE ...
配置环境变量
新建系统变量
变量名 | 变量值 |
---|---|
MAVEN_HOME |
D:\Software\apache-maven-3.9.9 |
编辑系统 Path
在 Path
中添加:
%MAVEN_HOME%\bin
验证配置是否成功
打开 命令提示符 (CMD) 或 PowerShell,输入:
mvn -v
若出现如下信息,则说明配置成功
Apache Maven 3.9.9 (xxxxx)
Maven home: D:\Software\apache-maven-3.9.9
Java version: 17.0.9, vendor: Oracle Corporation
Default locale: zh_CN, platform encoding: UTF-8
Maven配置
Maven 的全局配置文件是:
{MAVEN_HOME}/conf/settings.xml
它主要用于配置:
- 本地仓库路径;
- 镜像(国内源);
- 构建环境(JDK、Profile);
- 代理、服务器信息等。
配置本地仓库地址
xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- 本地仓库配置 -->
<localRepository>D:\maven-repo</localRepository>
...
</settings>
配置国内阿里镜像
xml
<mirrors>
<!-- 阿里云 Maven 公共仓库 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
配置JDK版本项目构建
xml
<profiles>
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
</profile>
</profiles>
完整配置模板
xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- 本地仓库路径 -->
<localRepository>D:\maven-repo</localRepository>
<!-- 镜像配置 -->
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
<!-- JDK 构建配置 -->
<profiles>
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
</profile>
</profiles>
</settings>
IDEA中配置
打开 Maven 设置
依次点击:
File → Settings → Build, Execution, Deployment → Build Tools → Maven
指定 Maven 目录
在右侧面板中找到:
-
Maven home path(Maven 主目录)
-
选择 自定义 Maven 安装目录,不要使用 IDEA 内置的版本;
-
点击
...
选择你本地安装的 Maven 路径,例如:D:\apache-maven-3.9.9
-
-
User settings file(用户配置文件)
-
选择你修改过的
settings.xml
文件,例如:D:\apache-maven-3.9.9\conf\settings.xml
-
-
Local repository(本地仓库)
-
如果你在
settings.xml
里已经配置过仓库路径,可以留空; -
否则这里可手动指定,例如:
D:\maven-repo
-
配置 JDK 构建环境
在:
File → Settings → Build, Execution, Deployment → Build Tools → Maven → Importing
设置:
- JDK for importer :选择你的项目使用的 JDK 版本(例如
17
)。 - VM options for importer:可选,一般留空即可。
验证配置是否成功
打开 IDEA 右侧的 Maven 工具栏,点击刷新按钮:
- 如果可以正确加载
pom.xml
; - 依赖正常下载;
- 执行命令无报错;
说明配置成功 。
在 IDEA 中验证 Maven 版本
你可以在 IDEA 终端(Terminal) 中输入:
bash
mvn -v
正常输出类似内容:
Apache Maven 3.9.9
Maven home: D:\apache-maven-3.9.9
Java version: 17.0.9, vendor: Oracle Corporation
表示环境变量与 IDEA 均已正确识别。
推荐配置小技巧
项目 | 推荐设置 |
---|---|
Maven Wrapper | 在多人协作项目中使用 mvnw ,避免版本不一致 |
自动导入 | 打开 "Import Maven projects automatically" |
插件下载慢 | 使用阿里云镜像(https://maven.aliyun.com/repository/public ) |
依赖缓存 | 本地仓库尽量设置到固态硬盘,提升构建速度 |
三、Maven工程
Maven工程的GAVP
GAVP是Maven项目坐标的核心组成部分,用于唯一标识一个Maven项目。
GAVP组成要素:
- GroupId (G)
- 定义:组织或公司标识符
- 命名规范:通常使用反向域名方式,如
com.example.project
- 作用:避免不同组织间的命名冲突
- ArtifactId (A)
- 定义:项目或模块的唯一标识符
- 命名规范:使用小写字母和连字符,如
my-web-app
- 作用:在同一groupId下唯一标识项目
- Version (V)
- 定义:项目的版本号
- 命名规范:遵循语义化版本控制,如
1.0.0
,2.1.3-SNAPSHOT
- 特殊版本:
SNAPSHOT
:快照版本,表示开发中的不稳定版本RELEASE
:发布版本
- Packaging §
- 定义:项目的打包方式
- 常用值:
jar
:Java应用程序库(默认值)war
:Web应用程序pom
:父项目或聚合项目ear
:企业级应用程序
Java SE工程
通过IDEA创建
Java Web工程
方式一:手动创建
创建一个java se工程
方式二:Maven Archetype模板创建
org.apache.maven.archetypes:maven-archetype-webapp
Maven工程项目结构
标准目录结构
bash
my-project/
├── pom.xml # 项目配置文件
├── src/ # 源代码根目录
│ ├── main/ # 主代码目录
│ │ ├── java/ # Java源代码
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── App.java
│ │ ├── resources/ # 资源文件
│ │ │ ├── application.properties
│ │ │ └── log4j.xml
│ │ └── webapp/ # Web应用文件(Web项目)
│ │ ├── WEB-INF/
│ │ │ └── web.xml
│ │ └── index.jsp
│ └── test/ # 测试代码目录
│ ├── java/ # 测试Java源代码
│ │ └── com/
│ │ └── example/
│ │ └── AppTest.java
│ └── resources/ # 测试资源文件
│ └── test.properties
└── target/ # 构建输出目录(自动生成)
├── classes/ # 编译后的class文件
├── test-classes/ # 编译后的测试class文件
└── my-project-1.0.0.jar # 打包后的文件
四、Maven工程构建
构建的概念
构建(build) 是把源码、资源、配置等变成可运行/可发布产物(artifact)的过程。常见内容包括:
- 源码编译(Java → class)
- 资源拷贝(resources → classpath)
- 单元测试、集成测试执行
- 打包(jar/war/zip/...)
- 生成文档/报告
- 将产物安装到本地仓库或发布到远程仓库
- (可选)静态检查、代码覆盖率、签名、发布到生产环境
构建要做到的是自动化、可复现、可验证------同一套构建在任何机器上应输出相同或可预测的产物。
构建的过程
构建的过程包括:
清理 → 编译 → 测试 → 打包 → 安装 → 部署
Maven的生命周期
Maven 构建工程时,会自动执行一系列步骤:
如 清理 → 编译 → 测试 → 打包 → 安装 → 部署 。
这整套「步骤顺序」称为 生命周期(Lifecycle)。
bash
Maven 生命周期
├── clean 生命周期(清理)
│ ├── pre-clean
│ ├── clean
│ └── post-clean
│
├── default 生命周期(构建)
│ ├── validate
│ ├── compile
│ ├── test
│ ├── package
│ ├── install
│ └── deploy
│
└── site 生命周期(生成站点)
├── pre-site
├── site
├── post-site
└── site-deploy
构建命令
命令类别 | 命令 | 功能说明 | 使用场景 |
---|---|---|---|
清理命令 | mvn clean |
清理target目录,删除编译结果 | 构建前清理旧文件 |
mvn clean compile |
清理后编译源代码 | 确保全新编译 | |
mvn clean test |
清理后运行测试 | 测试前清理环境 | |
mvn clean package |
清理后打包项目 | 生成干净的包文件 | |
mvn clean install |
清理后安装到本地仓库 | 本地部署新版本 | |
编译命令 | mvn compile |
编译主源代码 | 日常开发编译 |
mvn test-compile |
编译测试代码 | 运行测试前编译 | |
测试命令 | mvn test |
运行单元测试 | 验证代码正确性 |
mvn test -DskipTests |
跳过测试执行 | 快速构建跳过测试 | |
mvn test -Dtest=TestClass |
运行指定测试类 | 调试特定测试 | |
打包命令 | mvn package |
打包项目(jar/war等) | 生成可部署包 |
mvn package -DskipTests |
打包时跳过测试 | 快速打包 | |
安装命令 | mvn install |
安装到本地仓库 | 本地使用构建结果 |
mvn install -DskipTests |
安装时跳过测试 | 快速本地安装 | |
部署命令 | mvn deploy |
部署到远程仓库 | 团队共享构件 |
mvn deploy -DskipTests |
部署时跳过测试 | 快速远程部署 | |
验证命令 | mvn validate |
验证项目配置 | 检查项目完整性 |
mvn verify |
验证构建结果 | 发布前质量检查 | |
站点命令 | mvn site |
生成项目文档站点 | 生成项目文档 |
mvn site-deploy |
部署站点文档 | 发布项目文档 | |
依赖命令 | mvn dependency:tree |
显示依赖树 | 分析依赖关系 |
mvn dependency:list |
列出所有依赖 | 查看依赖清单 | |
mvn dependency:analyze |
分析依赖使用情况 | 优化依赖配置 | |
帮助命令 | mvn --version |
显示Maven版本 | 检查环境配置 |
mvn --help |
显示帮助信息 | 查看命令用法 | |
mvn help:effective-pom |
显示实际生效的POM | 调试配置问题 |
参数选项表
参数 | 功能说明 | 使用示例 |
---|---|---|
-DskipTests |
跳过测试执行 | mvn install -DskipTests |
-Dmaven.test.skip=true |
跳过测试编译和执行 | mvn package -Dmaven.test.skip=true |
-P profile |
激活指定profile | mvn install -P dev |
-pl module |
构建指定模块 | mvn install -pl module1 |
-am |
同时构建依赖模块 | mvn install -pl module1 -am |
-amd |
构建依赖当前模块的模块 | mvn install -pl module1 -amd |
-o |
离线模式 | mvn install -o |
-U |
强制更新快照版本 | mvn install -U |
-X |
显示调试信息 | mvn install -X |
-q |
静默模式 | mvn install -q |
-T n |
并行构建(n为线程数) | mvn -T 4 install |
-s settings.xml |
指定settings文件 | mvn -s /path/to/settings.xml |
生命周期阶段表
生命周期 | 阶段 | 说明 |
---|---|---|
clean | pre-clean | 清理前准备工作 |
clean | 清理上次构建结果 | |
post-clean | 清理后处理工作 | |
default | validate | 验证项目正确性 |
compile | 编译项目源代码 | |
test | 运行测试 | |
package | 打包项目 | |
install | 安装到本地仓库 | |
deploy | 部署到远程仓库 | |
site | pre-site | 生成站点前准备 |
site | 生成项目站点文档 | |
post-site | 生成站点后处理 | |
site-deploy | 部署站点文档 |
这个表格总结了Maven最常用的基础命令和参数,可以帮助开发者快速查找和使用Maven命令。
命令示例:
命令 | 实际执行的阶段 |
---|---|
mvn compile |
validate → compile |
mvn test |
validate → compile → test |
mvn package |
validate → compile → test → package |
mvn install |
validate → compile → test → package → install |
mvn deploy |
validate → compile → test → package → install → deploy |
Maven插件
插件(Plugin)是执行具体构建任务的工具,例如编译、打包、测试等;
每个插件中包含多个 目标(Goal);
插件通过 <plugin>
标签在 pom.xml
中配置;
插件通常与生命周期阶段(phase)绑定。
插件名称 | 主要目标 (Goal) | 功能说明 |
---|---|---|
maven-clean-plugin | clean |
清理 target 目录(默认绑定到 clean 阶段) |
maven-resources-plugin | resources:resources 、resources:testResources |
处理资源文件(过滤配置、拷贝资源) |
maven-compiler-plugin | compiler:compile 、compiler:testCompile |
编译主代码和测试代码 |
maven-surefire-plugin | surefire:test |
执行单元测试(JUnit、TestNG) |
maven-jar-plugin | jar:jar |
打包生成 .jar 文件 |
maven-war-plugin | war:war |
打包生成 .war 文件(Web 项目) |
maven-install-plugin | install:install |
安装构建结果到本地仓库 |
maven-deploy-plugin | deploy:deploy |
部署构建产物到远程仓库 |
maven-site-plugin | site:site 、site:deploy |
生成项目报告和站点 |
maven-dependency-plugin | dependency:tree 、copy 、analyze |
管理、分析依赖(查看依赖树、拷贝依赖) |
maven-shade-plugin | shade:shade |
生成可执行的"胖包"(包含依赖的 jar) |
maven-assembly-plugin | assembly:single |
打包成指定格式(zip/tar.gz/jar 等) |
maven-enforcer-plugin | enforce |
强制项目规则(如 JDK 版本、依赖冲突) |
maven-help-plugin | help:effective-pom 、help:effective-settings |
查看 Maven 最终解析配置 |
maven-archetype-plugin | archetype:generate |
快速创建 Maven 工程骨架 |
spring-boot-maven-plugin | spring-boot:run 、repackage |
Spring Boot 打包与运行(打成可执行 jar) |
exec-maven-plugin | exec:java |
执行 Java 主类(快速运行程序) |
通过IDEA可视化构建
- 清理项目
路径:Lifecycle → clean
双击即可执行
效果:删除 target
目录,清理旧编译产物。
2.编译项目
路径:Lifecycle → compile
编译 src/main/java
代码
输出:target/classes
目录
3.测试项目
路径:Lifecycle → test
执行所有测试类(src/test/java
)
插件:maven-surefire-plugin
4.打包项目
路径:Lifecycle → package
根据打包类型生成产物:
- 普通 Java 项目 →
.jar
- Web 项目 →
.war
输出目录:target/your-app-version.jar
- 安装项目
路径:Lifecycle → install
将打包结果安装到本地仓库(~/.m2/repository
),
供其他项目引用。
6.部署项目
路径:Lifecycle → deploy
上传构建结果到远程仓库(如 Nexus、私服)。
构建插件、命令、生命周期之间的关系
生命周期阶段 | 默认插件 | 作用 |
---|---|---|
validate | - | 验证项目 |
compile | maven-compiler-plugin | 编译源码 |
test | maven-surefire-plugin | 执行测试 |
package | maven-jar-plugin / maven-war-plugin | 打包 |
install | maven-install-plugin | 安装到本地仓库 |
deploy | maven-deploy-plugin | 部署到远程仓库 |
五、Mavne依赖管理
依赖的基本配置(GAV 坐标)
Maven 中每个依赖都有唯一坐标:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.3.2</version>
<scope>compile</scope>
<optional>false</optional>
</dependency>
标签 | 含义 |
---|---|
<groupId> |
组织或公司 ID(类似包名) |
<artifactId> |
模块名(唯一标识) |
<version> |
版本号 |
<scope> |
依赖作用范围(Scope) |
<optional> |
是否参与传递依赖 |
依赖版本统一管理
当多个子模块共用依赖时,不需要重复声明版本,可统一管理:
父 POM:
xml
<properties>
<spring.version>5.3.23</spring.version>
<junit.version>5.10.0</junit.version>
<slf4j.version>1.7.36</slf4j.version>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
子模块
xml
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- 不写 version -->
</dependency>
</dependencies>
Maven 会自动继承版本号。
依赖范围
xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
Maven依赖范围对比表
依赖范围(Scope) | 编译主代码 | 编译测试 | 运行测试 | 打包运行 | 传递性 | 典型用途 | 示例 |
---|---|---|---|---|---|---|---|
compile (默认) | ✓ | ✓ | ✓ | ✓ | ✓ | 项目主代码需要的依赖 | Spring Core, Commons Lang |
provided | ✓ | ✓ | ✓ | ✗ | ✗ | 由JDK或容器提供的依赖 | Servlet API, JSP API |
runtime | ✗ | ✓ | ✓ | ✓ | ✓ | 运行时需要但编译时不需要的依赖 | JDBC驱动, SLF4J实现 |
test | ✗ | ✓ | ✓ | ✗ | ✗ | 仅测试时需要的依赖 | JUnit, Mockito |
system | ✓ | ✓ | ✓ | ✗ | ✗ | 系统本地依赖(不推荐) | 本地jar包 |
import | - | - | - | - | - | 仅用于dependencyManagement | BOM导入 |
详细说明表
Scope | 详细说明 | 注意事项 |
---|---|---|
compile | 默认范围,适用于所有阶段 | 最常用的范围,会传递给依赖项目 |
provided | 编译和测试时需要,运行时由容器提供 | 不会传递,不会被打包 |
runtime | 编译时不需要,运行时需要 | 常用于实现类库 |
test | 仅在测试编译和执行阶段有效 | 不会传递,不会影响主代码 |
system | 类似provided,但需要指定本地路径 | Maven 3.9+已废弃,强烈不推荐使用 |
import | 仅用于dependencyManagement,导入BOM | 只能与type=pom一起使用 |
传递性依赖规则表
直接依赖Scope | 传递性依赖Scope |
---|---|
compile | 保持原样 |
provided | provided |
runtime | runtime |
test | 不传递 |
system | 不传递 |
使用场景对照表
场景 | 推荐Scope | 说明 |
---|---|---|
主要业务逻辑依赖 | compile | 如Spring框架、工具类库 |
Web容器API | provided | 如Servlet API、JSP API |
数据库驱动 | runtime | 编译时不需要,运行时必需 |
测试框架 | test | 仅在测试时使用 |
本地jar包 | system(不推荐) | 应该安装到本地仓库 |
BOM导入 | import | 在dependencyManagement中使用 |
排除依赖
当某个传递依赖版本冲突或不需要时,可使用 <exclusions>
排除:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
常用依赖命令
命令 | 说明 |
---|---|
mvn dependency:list |
查看依赖列表 |
mvn dependency:tree |
查看依赖树 |
mvn dependency:analyze |
分析依赖使用情况 |
mvn dependency:resolve |
强制解析依赖 |
mvn dependency:purge-local-repository |
清除本地缓存重新下载 |
build构建配置
xml
<build>
<!-- 项目构建的基础目录 -->
<directory>target</directory>
<!-- 构建后的最终文件名 -->
<finalName>${artifactId}-${version}</finalName>
<!-- 主源码目录 -->
<sourceDirectory>src/main/java</sourceDirectory>
<!-- 脚本源码目录 -->
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<!-- 测试源码目录 -->
<testSourceDirectory>src/test/java</testSourceDirectory>
<!-- 输出目录 -->
<outputDirectory>target/classes</outputDirectory>
<!-- 测试输出目录 -->
<testOutputDirectory>target/test-classes</testOutputDirectory>
<!-- 资源配置 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<targetPath>.</targetPath>
</resource>
</resources>
<!-- 测试资源配置 -->
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<!-- 插件配置 -->
<plugins>
<!-- 插件配置 -->
</plugins>
<!-- 插件管理 -->
<pluginManagement>
<!-- 插件版本管理 -->
</pluginManagement>
</build>
六、Maven依赖传递和依赖冲突
什么是依赖传递
依赖传递 是指:当一个 Maven 项目依赖另一个项目时,
它会自动获取该项目的依赖(间接依赖),不需要在 pom.xml 中手动声明。
A 依赖 B
B 依赖 C
则:
- A 直接依赖 B(direct dependency)
- B 直接依赖 C
- A 间接依赖 C(transitive dependency)
最终 A 的依赖树中会包含:
A
├─ B
└─ C
依赖传递特性
特性 | 说明 | 示例 |
---|---|---|
自动继承特 | 依赖 A 时,自动继承其传递依赖 B、C | A→B→C,A 自动获得 C |
多层传递特性 | 传递可多级链式传播 | A→B→C→D |
有效性受作用域限制 | 不同 scope 影响是否传递 | test 不传递 |
可控性(可排除) | 可使用 <exclusions> 阻断不想要的依赖 |
手动排除某个 jar |
依赖传递的作用范围
直接依赖 Scope | 传递依赖 Scope | 最终在项目中的 Scope |
---|---|---|
compile | compile | compile |
compile | runtime | runtime |
runtime | compile | runtime |
runtime | runtime | runtime |
test | 任意 | ❌ 不传递 |
provided | 任意 | ❌ 不传递 |
规则总结一句话:
test 、provided 不传递;
其余遵循"较小权限优先"(compile > runtime)
什么是依赖冲突
当多个依赖(直接或间接)引用了同一个库(相同 groupId
+ artifactId
)但版本不同,Maven 无法同时使用多个版本,就必须"选择"其中一个版本加载。这个"选择"过程称为 依赖冲突解析。
依赖冲突的表现
现象 | 原因 |
---|---|
⚠️ 类缺失(ClassNotFoundException ) |
使用了被排除或未加载的版本 |
⚠️ 方法缺失(NoSuchMethodError ) |
加载了不兼容版本 |
⚠️ 编译成功但运行报错 | 不同依赖加载的 jar 版本不一致 |
⚠️ 体积膨胀、打包重复 | 多版本 jar 同时打包 |
依赖冲突的特性
特性 | 说明 |
---|---|
1️⃣ 传递性特征 | 冲突常源于"传递依赖",不是直接依赖 |
2️⃣ 同名唯一特征 | 相同 groupId + artifactId 的依赖只能保留一个版本 |
3️⃣ 自动裁剪特征 | Maven 会自动根据规则选择一个版本加载 |
4️⃣ 非对称特征 | 冲突解决结果与依赖路径和声明顺序有关,不是随机的 |
依赖冲突产生的常见场景
多路径依赖
A → B → X:1.0
A → C → X:2.0
Maven 必须在 1.0 与 2.0 中择一。
间接依赖传递不同版本
A → B(依赖 commons-io:2.5)
→ C(依赖 commons-io:2.8)
父子模块依赖不同版本
parent → commons-lang3:3.9
child → commons-lang3:3.12.0
插件自带依赖版本不同
maven-compiler-plugin 使用 javax.annotation:1.3
项目使用 javax.annotation:1.2
Maven 的冲突解决原则
Maven 使用两步决策机制解决依赖冲突:
规则一:最短路径优先
在依赖树中,路径层级更浅(距离项目更近)的依赖版本优先。
示例:
A
├── B → X:1.0
└── C → D → X:2.0
结果:使用 X:1.0(路径更短)
规则二:先声明优先
当路径长度相同时,先在 pom.xml 中声明的依赖优先。
示例:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>B</artifactId> <!-- B → X:1.0 -->
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>C</artifactId> <!-- C → X:2.0 -->
</dependency>
</dependencies>
结果:X:1.0 被使用,因为 B 在 C 之前声明。
解决依赖冲突的常用方法
方法 | 用途 | 示例 |
---|---|---|
明确声明版本(直接依赖覆盖) | 手动指定最终生效版本 | <dependency><version>2.0</version></dependency> |
使用 <dependencyManagement> 统一版本 |
父模块集中控制依赖版本 | 在 parent 中定义版本,子模块不写版本 |
使用 <exclusions> 排除冲突依赖 |
从特定依赖中移除冲突项 | <exclusion> |
使用 <optional>true</optional> |
阻止依赖被传递给下游 | 在被依赖模块中设置 |
使用 mvn dependency:tree |
查看并分析依赖树 | 识别冲突来源 |
使用 mvn dependency:analyze |
检测未使用/重复依赖 | 清理多余依赖 |
七、Maven工程继承和聚合关系
继承关系(父子工程)
目的:解决多模块项目中的配置重复问题。比如,所有模块都使用相同的Spring Boot版本、JUnit版本等。如果在每个模块的POM中都单独定义,会导致版本不一致和维护困难。
关键元素:
- 在父POM 中:使用
<dependencyManagement>
和<pluginManagement>
来声明依赖和插件的版本。 - 在子POM 中:通过
<parent>
元素指向父POM。子模块在声明依赖时,如果该依赖在父POM的<dependencyManagement>
中已定义,则可以省略版本号,Maven会自动从父POM继承。
示例:
父工程 (parent-project/pom.xml)
xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 必须是pom -->
<!-- 依赖管理:这里只声明版本,不实际引入依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version> <!-- 统一管理版本 -->
</dependency>
</dependencies>
</dependencyManagement>
<!-- 插件管理 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
子模块 (parent-project/child-module/pom.xml)
xml
<project>
<modelVersion>4.0.0</modelVersion>
<!-- 声明父工程 -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<!-- 可选 -->
<relativePath>../pom.xml</relativePath> <!-- 父工程路径 -->
</parent>
<artifactId>child-module</artifactId>
<!-- 不需要定义groupId和version,默认从父POM继承 -->
<!-- 引入依赖,无需写版本号,版本由父POM的dependencyManagement决定 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引用同一父项目下的其他模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>myproject-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
子项目会继承父项目的:
<properties>
属性<dependencyManagement>
依赖管理<build>
插件管理<repositories>
仓库配置<reporting>
报告配置
但不会继承:
<modules>
模块声明<dependencies>
中的直接依赖(除非在 dependencyManagement 中定义)
聚合关系( 聚合工程)
目的 :将多个模块组合在一起,以便通过一个命令统一构建。你不需要分别进入每个模块目录去执行mvn
命令。
关键元素:
- 在聚合POM 中:使用
<modules>
来列出所有需要被一起构建的模块。
示例:
聚合工程 (aggregator-project/pom.xml)
xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>aggregator-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 必须是pom -->
<!-- 声明要聚合的模块 -->
<modules>
<module>module-a</module>
<module>module-b</module>
<module>module-c</module>
</modules>
</project>
项目目录结构:
bash
aggregator-project/
├── pom.xml <-- 聚合POM
├── module-a/
│ └── pom.xml <-- 模块A(可以有自己的父POM,不一定是这个聚合POM)
├── module-b/
│ └── pom.xml
└── module-c/
└── pom.xml
当你在 aggregator-project
目录下执行 mvn clean install
时,Maven会按照**反应堆(Reactor)**计算的顺序(考虑模块间的依赖关系)依次构建 module-a
, module-b
, module-c
。
最常见的场景:二者合一
在标准的Maven多模块项目中,最常用的模式是让顶层POM同时充当父POM和聚合POM。
示例 (root-project/pom.xml):
xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>root-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging> <!-- 关键! -->
<!-- 1. 作为聚合工程:声明模块 -->
<modules>
<module>core-service</module>
<module>web-app</module>
<module>data-access</module>
</modules>
<!-- 2. 作为父工程:统一管理依赖和插件 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<java.version>11</java.version>
</properties>
</project>
在这种模式下:
- 你在根目录执行
mvn clean install
,Maven会按顺序构建所有子模块(聚合的功能)。 - 所有子模块通过
<parent>
指向这个根POM,从而继承依赖版本、Java版本等配置(继承的功能)。 - 子模块之间还可以相互引用依赖。
在实际应用中,将它们结合使用是最高效和标准的做法。
八、Profiles多环境配置
- 不同环境(dev/test/prod)使用不同依赖和配置
- 激活方式:命令行参数、系统属性、操作系统等
什么是 Maven Profiles
Profile
是 Maven 提供的一个机制,
用于在不同的 构建环境(Environment) 下,使用不同的配置项,比如:
- 不同环境的数据库配置;
- 不同的依赖或插件版本;
- 不同的构建参数;
- 不同的打包方式。
简单理解:Maven Profiles = 多环境配置模板
类似于:Spring Boot 的
application-dev.yml
、application-prod.yml
。
为什么要用 Profiles
开发场景举例:
环境 | 数据库 | 部署路径 | 备注 |
---|---|---|---|
开发环境(dev) | localhost:3306/test | 本地 | 调试使用 |
测试环境(test) | 10.0.0.12:3306/test | 测试服务器 | 测试团队使用 |
生产环境(prod) | rds.aliyun.com:3306/prod | 云服务器 | 实际部署 |
使用 profiles
,你可以:
- 在一个
pom.xml
中维护多种环境配置; - 使用命令行一键切换;
- 避免每次打包都手动改配置。
Profiles 的基本结构
在 pom.xml
中添加 <profiles>
节点:
<profiles>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<properties>
<env>development</env>
<db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
<db.username>root</db.username>
<db.password>123456</db.password>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 测试环境 -->
<profile>
<id>test</id>
<properties>
<env>test</env>
<db.url>jdbc:mysql://10.0.0.12:3306/test_db</db.url>
<db.username>test</db.username>
<db.password>123456</db.password>
</properties>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<env>production</env>
<db.url>jdbc:mysql://rds.aliyun.com:3306/prod_db</db.url>
<db.username>admin</db.username>
<db.password>******</db.password>
</properties>
</profile>
</profiles>
激活 Profiles 的几种方式
方式1:命令行激活(最常用)
mvn clean package -Pdev
mvn clean package -Ptest
mvn clean package -Pprod
方式2:默认激活
通过:
<activation>
<activeByDefault>true</activeByDefault>
</activation>
设置默认激活的 profile。
方式3:通过系统属性激活
<activation>
<property>
<name>env</name>
<value>dev</value>
</property>
</activation>
然后执行:
mvn clean install -Denv=dev
方式4:通过操作系统属性激活
<activation>
<os>
<name>Windows 10</name>
</os>
</activation>
适合针对不同操作系统(Windows/Linux)使用不同的配置。
在 properties
中使用 Profile 变量
例如在 src/main/resources/config.properties
中引用:
db.url=${db.url}
db.username=${db.username}
db.password=${db.password}
Maven 在构建时会自动用当前激活的 Profile 的属性值进行替换。
与 settings.xml 的配合使用
除了项目 pom.xml
,你也可以在用户级的 settings.xml
(通常在 ~/.m2/
目录)中配置全局 Profile。
<settings>
<profiles>
<profile>
<id>aliyun</id>
<repositories>
<repository>
<id>aliyun-maven</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>aliyun</activeProfile>
</activeProfiles>
</settings>
👉 这个 profile 会自动启用,不需要在命令行输入 -Paliyun
。
Profiles 与打包结合
Profiles 不仅能定义属性,还能定义不同环境的打包行为。例如:
<profile>
<id>prod</id>
<build>
<finalName>myapp-prod</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
打包命令:
mvn clean package -Pprod
生成的文件名为 myapp-prod.jar
。
Profiles 与多模块项目结合
在多模块项目中,Profiles 通常定义在父工程中,用于统一控制所有子模块的环境配置。
父 POM:
<profiles>
<profile>
<id>test</id>
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>
</profile>
</profiles>
执行:
mvn clean package -Ptest
即可在测试环境下一次构建所有模块。
九、Maven私服
Maven私服简介
Maven 私服 是一种中间仓库 ,
位于开发者与远程中央仓库(Maven Central)之间。
它的主要作用是:
- 代理远程中央仓库,加速依赖下载;
- 缓存依赖(避免重复下载);
- 存放公司内部私有 jar;
- 统一依赖版本管理;
- 提高构建速度与安全性。
Maven 仓库的类型
仓库类型 | 说明 |
---|---|
本地仓库 | 每个开发者电脑上的仓库(默认在 ~/.m2/repository ) |
远程仓库 | Maven 官方或第三方托管的仓库(如 Maven Central) |
私服(私有仓库) | 公司或团队内部搭建的代理仓库(如 Nexus、Artifactory) |
私服相当于一个中转站:
开发者 → 私服 → 远程中央仓库
常见的私服产品
工具 | 开源 | 企业支持 | 特点 |
---|---|---|---|
Sonatype Nexus Repository | ✅ | ✅ | 使用最广泛,配置简单,性能稳定 |
JFrog Artifactory | ✅ | ✅ | 支持多语言(Maven/NPM/Docker 等) |
Apache Archiva | ✅ | ❌ | 较老,社区维护少 |
目前企业几乎都使用 Nexus 3.x+ ,所以以下讲解基于 Nexus 私服。
Nexus下载安装
Nexus Repository Manager 是由 Sonatype 开发的 仓库管理工具,用于:
- 管理 Maven、npm、Docker 等多种依赖包;
- 搭建公司内部的 Maven 私服;
- 代理中央仓库,加速依赖下载;
- 托管内部开发产物,方便共享与版本管理。
下载地址
前往 Sonatype 官网:
https://help.sonatype.com/repomanager3/download
选择 Nexus Repository OSS 版本(免费开源版)下载。
例如:
nexus-3.68.1-01-unix.tar.gz
解压与目录说明
# Linux / Mac
tar -zxvf nexus-3.68.1-01-unix.tar.gz -C /usr/local/
cd /usr/local/nexus-3.68.1-01
# Windows
解压到 D:\nexus\
目录结构:
nexus-3.68.1-01/
├── bin/ # 启动脚本目录
│ ├── nexus # Linux 启动脚本
│ └── nexus.exe # Windows 启动脚本
├── etc/ # 配置文件目录
├── lib/ # 依赖库目录
├── public/ # 静态资源目录
└── sonatype-work/ # Nexus 工作目录(仓库存储区)
修改数据存储路径(可选)
默认工作目录为 ../sonatype-work/nexus3
你也可以修改:
vi bin/nexus.vmoptions
找到:
-Dkaraf.data=../sonatype-work/nexus3
修改为你希望的路径,比如:
-Dkaraf.data=/data/nexus-data
启动 Nexus
Linux / Mac
cd /usr/local/nexus-3.68.1-01/bin
./nexus start
Windows
双击:
nexus.exe /run
或命令行执行:
nexus.exe /run
访问 Web 界面
默认端口:8081
浏览器访问:
首次访问需要输入初始密码。
初始管理员账号密码
默认用户名:
admin
密码文件位置:
sonatype-work/nexus3/admin.password
打开文件复制其中的字符串作为初始密码。
首次登录后会要求你:
- 修改密码;
- 设置匿名访问;
- 配置仓库类型。
在 Maven 中配置 Nexus 私服
编辑 settings.xml
(位于 Maven 安装目录的 conf 下或用户目录 ~/.m2/settings.xml
):
xml
<mirrors>
<mirror>
<id>nexus-public</id>
<mirrorOf>*</mirrorOf>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
</mirrors>
<servers>
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>你的密码</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>你的密码</password>
</server>
</servers>
然后在项目的 pom.xml
中添加:
xml
<distributionManagement>
<repository>
<id>nexus-releases</id>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
验证是否成功
执行:
mvn clean install
查看是否从 Nexus 仓库下载依赖(控制台会出现 nexus 的下载链接)。
上传测试:
mvn deploy
构建的包会被上传到 Nexus 的 Hosted 仓库中。
Nexus 私服架构图

Nexus 中仓库类型
仓库类型 | 说明 | 举例 |
---|---|---|
proxy(代理仓库) | 代理远程中央仓库或第三方仓库 | 代理 Maven Central |
hosted(宿主仓库) | 存放内部发布的 jar 包 | 公司自研模块、内部工具类 |
group(组合仓库) | 将多个仓库聚合为一个统一访问入口 | 将 hosted + proxy 组合 |
十、与 CI/CD 集成
- Maven 与 Jenkins 的自动化构建流程
- 使用
mvn deploy
发布构件到服务器
CI/CD 与 Maven 的关系
名称 | 作用 |
---|---|
Maven | 项目构建工具,负责编译、测试、打包、部署 |
Jenkins | 持续集成/持续部署(CI/CD)工具,自动化执行 Maven 构建 |
Nexus | 构件仓库,用于存放 Maven 构建的 jar/war 包 |
Git | 代码版本管理系统,Jenkins 从 Git 拉取代码 |
简单来说:
Jenkins 自动拉取 Git 代码 → 调用 Maven 进行构建测试 → 打包产物(jar/war)→
mvn deploy
发布到 Nexus 或服务器。
Maven 与 Jenkins 的自动化构建流程图
