Maven使用:依赖管理和项目构建工具
目录
1、介绍
2、核心概念
2.1 pom
2.2 依赖管理(坐标)
2.3 仓库
2.4 生命周期和阶段
2.5 插件和目标
3、优缺点
4、使用
4.1 pom文件示例
4.2 常用命令示例
4.3 常见问题
4.3.1 解决Jar包冲突
5、Maven vs Gradle
1、介绍
核心定义:Maven 是一个基于 POM(Project Object Model,项目对象模型) 的软件项目管理和构建自动化工具。可以把它理解为:
-
一个构建工具:像 Make、Ant、Gradle 一样,它能编译代码、运行测试、打包应用。
-
一个依赖管理工具:它能自动下载和管理你的项目所依赖的第三方库(JAR 包)。
-
一个项目生命周期管理工具:它定义了一套标准的项目构建生命周期,使得项目的构建过程变得标准化和可重复。
-
一个项目信息管理工具:它能基于 POM 生成项目文档、站点报告、依赖关系图等。
Maven 的核心思想:约定优于配置。Maven 为项目定义了一套标准的目录结构和默认的构建生命周期。目录结构:
src/main/java/ --> 项目Java源代码resources/ --> 项目资源文件(如配置文件)test/java/ --> 测试Java源代码resources/ --> 测试资源文件
target/ --> 编译输出目录(编译后自动生成)
pom.xml --> 项目对象模型文件
2、核心概念
2.1 pom
POM 是 Maven 的灵魂。它是一个名为 pom.xml 的 XML 文件,位于项目的根目录下。这个文件描述了项目的所有信息:
-
项目基本信息:
groupId(组织/公司标识),artifactId(项目标识),version(版本号)。这三个属性唯一确定一个项目,合称为 GAV(坐标)。 -
项目依赖:声明项目所依赖的外部库。
-
插件:声明在构建过程中需要使用的插件和目标。
-
构建配置:可以自定义源码目录、输出目录等(但通常不建议违背约定)。
-
父 POM:支持继承,可以从一个父 POM 继承通用配置,这促进了配置的复用。一个父POM通过
<modules>管理多个子模块。父POM的打包方式(packaging)必须是pom。
2.2 依赖管理(坐标)
-
坐标系统:通过
groupId,artifactId,version可以唯一地在 Maven 仓库中找到任何一个库。 -
依赖管理:在父POM中使用
<dependencyManagement>统一管理所有子模块的依赖版本,子模块只需声明groupId和artifactId,无需指定version,保证了项目依赖版本的一致性。 -
传递性依赖:如果项目依赖了 A库,而 A库又依赖了 B库和 C库,Maven 会自动将 A, B, C 都引入到项目中。
-
依赖范围:<scope>用来控制依赖与三种 classpath(编译、测试、运行)的关系。
-
compile:默认范围,对编译、测试、运行都有效。 -
provided:编译和测试时有效,运行时由 JDK 或容器提供(如 Servlet API)。 -
runtime:测试和运行时有效(如 JDBC 驱动)。 -
test:仅在测试时有效(如 JUnit)。 -
system:与provided类似,但需要显式指定本地路径(不推荐)。
-
-
依赖排除:<exclusions>可以排除特定的传递性依赖,解决版本冲突。
-
依赖调解:当出现多个版本的同一依赖时,Maven 遵循 “就近原则” 和 “第一声明原则” 来解决冲突。
-
就近原则: 依赖路径长度相同的情况下,在依赖树中离项目最近的版本被优先使用。“近”指的是在依赖树中的层级深度。
-
先声明优先原则: 依赖路径长度相同的情况下,在POM中先声明的依赖其传递的版本被优先使用。
-
如何排查: 使用
mvn dependency:tree命令查看依赖树,是解决Jar包冲突的神器。
-
2.3 仓库
仓库是存放所有项目构件(JAR, WAR, POM 等)的地方。
-
本地仓库:在本机上的一个目录(默认是
~/.m2/repository)。Maven 会优先从这里查找依赖。 -
中央仓库:由 Maven 社区维护的全球公共仓库。当声明的依赖在本地仓库找不到时,Maven 会自动去这里下载。
-
远程仓库(私服):公司或组织在内网搭建的私有仓库。它的作用:
-
加速构建(缓存中央仓库的构件)。
-
部署公司内部的项目模块。
-
存放无法从中央仓库获取的第三方库(如 Oracle 驱动)。
-
工作流程:本地项目 -> 本地仓库 -> 私服(如有) -> 中央仓库。
maven仓库地址:https://mvnrepository.com/

2.4 生命周期和阶段
Maven 的生命周期是一个抽象的、定义良好的构建过程序列。它包含三个内置的生命周期:
-
clean:清理项目。
-
pre-clean -
clean(删除target目录) -
post-clean
-
-
default(或
build):构建和部署项目(核心)。-
validate(验证项目正确性) -
compile(编译源代码) -
test(运行单元测试) -
package(打包,如 JAR, WAR) -
verify(对集成测试结果进行检查) -
install(将包安装到本地仓库,供其他本地项目使用) -
deploy(将包部署到远程仓库,供其他开发者使用,如Nexus)
-
-
site:生成项目站点和文档。
-
site(生成站点文档) -
site-deploy(部署站点到服务器)
-
关键点:当执行一个阶段时,Maven 会自动执行该阶段之前的所有阶段。例如,执行 mvn package,Maven 会依次执行 validate, compile, test,最后才是 package。
2.5 插件和目标
生命周期本身不做任何实际工作,所有工作都是由插件来完成的。
-
插件:是 Maven 功能的实际实现者,本质是一个或多个目标的集合。
-
目标:是插件中的一个具体任务。
-
例如:
maven-compiler-plugin插件有compile目标(用于编译)和testCompile目标(用于编译测试代码)。
-
-
常用插件:
maven-compiler-plugin(指定JDK版本),maven-surefire-plugin(运行测试),maven-jar-plugin(打包)。
生命周期阶段与插件目标的绑定:Maven 核心为每个生命周期阶段都绑定了默认的插件目标。例如,compile 阶段默认绑定的是 maven-compiler-plugin 的 compile 目标。
可以通过配置 pom.xml 来使用自定义插件或修改默认插件的配置。
3、优缺点
优点:
-
标准化和一致性:约定优于配置使得项目结构统一,新人上手快。
-
强大的依赖管理:自动处理依赖和冲突,极大地简化了 jar 包管理。
-
丰富的插件生态:有大量成熟的插件支持各种功能(如 Tomcat 部署、代码质量检查等)。
-
良好的继承和聚合机制:支持多模块项目,非常适合大型项目。
缺点:
-
灵活性较差:由于严格的约定,对于不遵循标准结构的项目配置起来会比较复杂。
-
XML 配置繁琐:
pom.xml会变得非常冗长,特别是依赖很多的时候。 -
学习曲线:虽然入门简单,但要深入理解其生命周期、插件机制、依赖调解等,需要一定学习成本。
-
构建速度:在某些场景下,相比 Gradle 等新工具,构建速度可能较慢。
4、使用
4.1 pom文件示例
<?xml version="1.0" encoding="UTF-8"?>
<!-- POM 模型版本,Maven 2/3 都用 4.0.0 -->
<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><!-- ========== 项目坐标 GAV - 唯一标识这个项目 ========== --><groupId>com.example</groupId> <!-- 公司/组织域名反写 --><artifactId>my-simple-app</artifactId> <!-- 项目名 --><version>1.0.0</version> <!-- 版本号 --><packaging>jar</packaging> <!-- 打包方式:jar, war, pom等 --><!-- ========== 项目属性配置 ========== --><properties><!-- 定义项目编码为 UTF-8,避免中文乱码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 指定 Java 版本 --><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><!-- ========== 项目依赖管理 ========== --><dependencies><!-- 一个生产环境依赖:日志框架 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version><!-- scope 默认是 compile,表示编译、测试、运行都需要 --></dependency><!-- 一个测试环境依赖:JUnit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><!-- scope 为 test,表示只在测试时需要 --><scope>test</scope></dependency></dependencies><!-- ========== 构建配置 ========== --><build><plugins><!-- Maven 编译器插件配置 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><!-- 使用 properties 中定义的版本 --><source>11</source><target>11</target><!-- 显式指定编码 --><encoding>UTF-8</encoding></configuration></plugin><!-- 打包时跳过测试的配置示例 --><!--<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0</version><configuration><skipTests>true</skipTests></configuration></plugin>--></plugins></build>
</project>
4.2 常用命令示例
# Maven 常用命令示例# 1. 项目创建相关命令
# 创建普通的 Maven Java 项目
mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -Dversion=1.0.0-SNAPSHOT# 创建 Maven Web 项目
mvn archetype:generate -DgroupId=com.example -DartifactId=my-web-app -DarchetypeArtifactId=maven-archetype-webapp# 2. 项目构建生命周期核心命令
# 编译项目主代码
mvn compile# 编译测试代码
mvn test-compile# 运行所有测试
mvn test# 打包项目(JAR/WAR)
mvn package# 将项目安装到本地仓库,供其他项目依赖
mvn install# 清理项目(删除target目录)
mvn clean# 常用组合:清理后打包
mvn clean package# 常用组合:清理后安装,跳过测试
mvn clean install -Dmaven.test.skip=true# 3. 测试相关控制命令
# 跳过测试运行(但会编译测试代码)
mvn package -DskipTests# 完全跳过测试编译和运行
mvn package -Dmaven.test.skip=true# 4. 依赖管理相关命令
# 查看项目已解析依赖
mvn dependency:list# 查看依赖树(排查依赖冲突非常有用)
mvn dependency:tree# 下载依赖项的源码
mvn dependency:sources# 5. 项目部署与发布
# 将最终包部署到远程仓库(需配置distributionManagement)
mvn deploy# 常用组合:使用生产配置清理部署
mvn clean deploy -P prod# 6. 信息查看与验证命令
# 验证项目是否正确且所有必要信息可用
mvn validate# 查看有效POM(合并了父POM、默认设置等后的实际生效POM)
mvn help:effective-pom# 检查依赖是否有更新
mvn versions:display-dependency-updates# 7. 插件与自定义执行
# 使用Exec插件运行Main类(需配置插件)
mvn exec:java -Dexec.mainClass="com.example.Main"# 使用Jetty插件运行Web应用(需配置插件)
mvn jetty:run# 使用Tomcat插件运行Web应用(需配置插件)
mvn tomcat7:run# 使用spring-boot插件运行应用(需配置插件)
mvn spring-boot:run# 8. 多模块项目构建命令
# 构建指定模块及其依赖的模块
mvn clean install -pl module-a -am# 构建指定模块及依赖于它的模块
mvn clean install -pl module-a -amd# 仅构建父项目
mvn clean install -N# 说明
# -pl:指定要构建的模块
# -am:同时构建依赖模块
# -amd:同时构建依赖此模块的模块
# -N:不递归构建子模块# 9. 其他实用命令和参数
# 强制检查远程仓库的更新(针对SNAPSHOT依赖)
mvn clean install -U# 开启调试信息输出
mvn clean install -X# 只输出错误信息(安静模式)
mvn clean install -q# 离线模式(不使用远程仓库)
mvn clean install -o# 指定使用特定配置文件(如开发、测试、生产环境)
mvn clean install -P dev
4.3 常见问题
4.3.1 解决Jar包冲突
-
第一步:
mvn dependency:tree查看依赖树。 -
第二步: 分析冲突来源,使用
<exclusion>排除不需要的传递性依赖。 -
第三步: 也可以直接在当前POM中显式声明一个想要的版本,利用Maven的就近原则覆盖传递过来的版本。
5、Maven vs Gradle
Gradle 是后起之秀,它结合了 Maven 的依赖管理和 Ant 的灵活性。
| 特性 | Maven | Gradle |
|---|---|---|
| 配置语言 | XML | Groovy / Kotlin DSL(更简洁、灵活) |
| 性能 | 较慢 | 更快(得益于增量构建和构建缓存) |
| 灵活性 | 低(约定严格) | 高(可自定义任务和逻辑) |
| 学习曲线 | 平缓 | 相对陡峭(需要学习 DSL) |
| 成熟度 | 非常成熟,生态稳定 | 非常成熟,是 Android 官方构建工具 |
选择建议:
-
Maven:适合传统、标准的 Java 项目,团队希望配置简单、约定统一。
-
Gradle:适合需要高度定制化构建流程、追求构建性能的项目(如大型多模块项目、Android 项目)。
