Maven从入门到使用
文章目录
- Maven从入门到使用
-
- 前言
- 一、Maven概述
-
- [1.1 Maven vs Gradle](#1.1 Maven vs Gradle)
- 二、Maven安装与配置
-
- [2.1 下载与安装](#2.1 下载与安装)
- [2.2 配置本地仓库和镜像](#2.2 配置本地仓库和镜像)
- [2.3 IDEA中配置Maven](#2.3 IDEA中配置Maven)
- 三、pom.xml详解
-
- [3.1 基本结构](#3.1 基本结构)
- [3.2 项目坐标三要素](#3.2 项目坐标三要素)
- [3.3 依赖管理](#3.3 依赖管理)
- [3.4 依赖范围(scope)](#3.4 依赖范围(scope))
- [3.5 依赖传递与排除](#3.5 依赖传递与排除)
- 四、Maven生命周期
-
- [4.1 clean生命周期](#4.1 clean生命周期)
- [4.2 default生命周期](#4.2 default生命周期)
- [4.3 site生命周期](#4.3 site生命周期)
- 五、Maven常用命令
- 六、Maven插件
- 总结
- [✅ 亮点总结](#✅ 亮点总结)
- 适用场景
- 扩展方向
前言
在Java开发中,项目构建和依赖管理是每天都要面对的问题。手工下载jar包、管理版本、处理传递性依赖------这些繁琐的工作Maven都能帮你自动化完成。作为Java生态中最主流的构建工具,Maven几乎成为了每个Java开发者的必备技能。
为什么要学Maven? 试想一下:你加入一个新项目,手动下载了spring-context.jar,却发现它还依赖spring-core.jar、spring-beans.jar等十几个jar包;你又逐个下载这些依赖的jar包,结果版本还不兼容,项目启动直接报ClassNotFoundException。这种经历是每个Java开发者都曾有过的噩梦。Maven的出现彻底解决了这些问题------你只需在pom.xml中声明一个依赖,Maven就会自动帮你下载所有相关的jar包,并且统一管理版本。
本文将从安装配置讲起,带你全面掌握Maven的核心用法。无论你是刚入行的新人还是准备面试的老兵,掌握Maven都是Java开发的必修课。在面试中,Maven相关的知识点(如依赖冲突解决、生命周期理解、多模块构建)同样是高频考点。
一、Maven概述
Maven是Apache旗下的开源项目管理和构建工具。基于**项目对象模型(POM)**的概念,Maven可以管理项目的构建、报告和文档。它的核心功能包括:
- 依赖管理:自动下载和管理项目所需的jar包及传递性依赖
- 项目构建:统一的项目结构和生命周期,一键编译、测试、打包
- 模块化管理:支持多模块项目,便于大型项目拆分
1.1 Maven vs Gradle
虽然Gradle近年来逐渐流行,但Maven依然是企业级项目的首选构建工具。它规范的约定优于配置、稳定的插件生态和庞大的仓库支持,使得Maven在Spring Boot等主流框架中广泛使用。
选择建议:如果你是初学者或者在传统企业级项目开发,优先选择Maven,社区成熟、资料丰富、团队普及度高;如果你从事Android开发或需要高度定制化的构建流程,可以考虑Gradle。实际工作中,大多数Java后端项目仍然使用Maven,所以学好Maven的性价比极高。Spring Initializr默认也是生成Maven项目,这也是一个侧面证明。
二、Maven安装与配置
2.1 下载与安装
-
访问Maven官网
https://maven.apache.org下载最新版本 -
解压到本地目录,例如
D:\apache-maven-3.9.6 -
配置环境变量:
MAVEN_HOME=D:\apache-maven-3.9.6
在PATH中添加 %MAVEN_HOME%\bin -
验证安装:
bash
mvn -version
如果显示Maven版本号和JDK信息,说明安装成功。
常见安装问题:
- mvn不是内部命令 :说明PATH环境变量未生效,建议重新打开命令行窗口再试;如果仍然不行,检查PATH路径是否正确配置到
bin目录。 - JAVA_HOME未配置:Maven运行时依赖JAVA_HOME环境变量,如果报错"JAVA_HOME is not defined",需要先配置JDK并设置JAVA_HOME。
- 版本不一致 :确保Maven版本与IDEA版本兼容,一般来说Maven 3.6+配合IDEA 2020+都没有问题。可以在命令行执行
echo %JAVA_HOME%和echo %MAVEN_HOME%来确认环境变量是否生效。
2.2 配置本地仓库和镜像
为什么要配置镜像? Maven中央仓库的默认地址在国外,如果不配置镜像,下载依赖的速度会非常慢,甚至可能超时失败。国内开发者通常配置阿里云镜像来加速。
编辑 conf/settings.xml 文件,配置阿里云镜像加速依赖下载:
xml
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Central</name>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>
配置本地仓库路径(默认为 ${user.home}/.m2/repository):
xml
<localRepository>D:\maven-repository</localRepository>
本地仓库的作用:Maven下载的所有jar包都会缓存到本地仓库中,下次使用时直接从本地读取,不需要重复下载。建议将本地仓库放在非系统盘(如D盘),避免重装系统后丢失依赖,也避免占用C盘空间。另外,本地仓库路径中不要包含中文和空格,否则某些插件可能会出现兼容性问题。
2.3 IDEA中配置Maven
在IDEA中,进入 File → Settings → Build → Build Tools → Maven,设置:
- Maven home path:指向Maven安装目录
- User settings file:指向你配置的settings.xml
三、pom.xml详解
pom.xml是Maven项目的核心配置文件,定义了项目的基本信息和依赖关系。
3.1 基本结构
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>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- 属性定义 -->
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
pom.xml 文件的根元素是 <project>,xmlns属性声明了命名空间和schema位置。<modelVersion> 固定为4.0.0,这是Maven 2/3版本的标准。<packaging> 元素指定打包方式,常见的值有jar(Java项目)、war(Web项目)、pom(父工程,只做依赖管理)。如果不指定,默认值为jar。
packaging为pom的场景:在多模块项目或作为BOM(Bill of Materials)统一管理依赖版本时使用。面试中经常问到的"父POM"就是将packaging设置为pom。
3.2 项目坐标三要素
- groupId :项目组织标识,通常是域名反写,如
com.alibaba - artifactId :项目名称,如
fastjson - version:版本号,SNAPSHOT表示快照版本(开发中),RELEASE表示正式版本
这三个要素共同唯一标识一个项目,Maven仓库正是通过坐标来定位jar包的。
版本号中的SNAPSHOT含义 :SNAPSHOT版本表示当前处于开发阶段,是不稳定的。Maven对于SNAPSHOT版本会定期检查更新(默认每天一次),即使本地有缓存也会尝试拉取最新版本。这就是为什么有些人代码没改但构建结果不同------可能是某个SNAPSHOT依赖被更新了。正式发布时一定要将SNAPSHOT去掉,改为RELEASE版本。想强制更新SNAPSHOT依赖,可以在构建时加上-U参数。
3.3 依赖管理
依赖管理是Maven最核心的功能。你只需在pom.xml中声明项目需要哪些jar包,Maven会自动从中央仓库(或你配置的镜像仓库)下载jar包及其传递性依赖。这远比手动下载jar包、添加到classpath的方式高效且可靠。
xml
<dependencies>
<!-- JUnit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
依赖声明的三个要素 :groupId + artifactId + version 确定一个惟一的jar包。在IDEA中,如果不知道某个依赖的坐标,可以在Maven工具窗口中搜索,或访问 https://mvnrepository.com 查询。IDE还提供了依赖分析功能,右键pom.xml → Diagrams → Show Dependencies,可以直观地看到所有依赖之间的关系。
常见错误 :忘记指定scope导致jar包出现在不必要的位置。比如将servlet-api的scope设为compile(默认值),部署到Tomcat时就会与容器自带的servlet-api冲突,报ClassCastException或LinkageError。另一个常见问题是版本号拼写错误,Maven不会提示你,只是默默下载不到jar包,编译时才会报错。
3.4 依赖范围(scope)
| scope | 说明 | 举例 |
|---|---|---|
| compile | 默认范围,编译、运行、发布都有效 | spring-core |
| provided | 编译和测试有效,运行时由容器提供 | servlet-api |
| runtime | 运行和测试有效,编译不需要 | mysql-connector |
| test | 仅测试有效 | junit |
| system | 本地jar包,不通过Maven仓库获取 | 特定本地jar |
scope理解误区:很多初学者搞不清provided和runtime的区别。记住一个简单口诀------provided是"容器提供"(如Tomcat提供servlet-api),runtime是"运行时才需要"(如JDBC驱动,编译时只需要接口)。如果面试中被问到Maven的scope,重点讲compile/provided/runtime/test四种即可,system很少使用且不推荐。
3.5 依赖传递与排除
Maven会自动引入依赖的依赖(传递性依赖)。当遇到版本冲突时,遵循最短路径优先 和先声明优先原则。
什么是依赖冲突? 假设项目A依赖了B(v1.0)和C,而C又依赖了B(v2.0)。Maven最终会选择哪个版本的B?这是面试中的高频问题。Maven的解决策略是:1)最短路径优先------A→B(路径长度为1)比A→C→B(路径长度为2)更短,选择B v1.0;2)如果路径长度相同,则先声明的优先。这种机制虽然自动,但也可能引入不期望的版本,导致运行时异常。
可以通过以下方式排除不需要的传递依赖:
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>
排除依赖的常见场景 :spring-boot-starter-web默认内嵌了Tomcat,如果你想换成Undertow,就需要排除tomcat再引入undertow。另一个场景是日志框架冲突------项目中同时存在log4j和logback会导致日志输出异常,需要排除其中一个。排查依赖冲突时,使用 mvn dependency:tree 命令查看完整的依赖树是非常有效的诊断手段。
四、Maven生命周期
Maven拥有三大独立的生命周期:
为什么要理解生命周期? Maven的生命周期是面试的常见考点,也是日常开发中理解构建流程的基础。当你执行mvn package时,它实际会按顺序执行validate→compile→test→package。这意味着即使你只写了package命令,代码也会先被编译、然后跑测试。如果测试失败,package也会失败。这就是为什么有时候用-DskipTests跳过测试来加速构建。
4.1 clean生命周期
用于清理项目,删除target目录下的构建产物。
bash
mvn clean
4.2 default生命周期
核心构建生命周期,包含以下关键阶段:
| 阶段 | 说明 |
|---|---|
| compile | 编译项目源代码 |
| test | 运行单元测试 |
| package | 打包(jar/war) |
| install | 安装到本地仓库 |
| deploy | 部署到远程仓库 |
注意 :生命周期中的每个阶段都会先执行它前面的所有阶段。例如执行mvn install,实际执行顺序是:validate→compile→test→package→install。这就是"生命周期"的含义------不可跳跃,只能按顺序执行。面试中经常考察这个知识点。
bash
mvn compile # 仅编译
mvn package # 打包(会依次执行compile→test→package)
mvn clean install # 清理后安装到本地仓库
4.3 site生命周期
生成项目站点文档。
bash
mvn site
实用技巧 :clean生命周期与default生命周期是独立的,所以必须使用mvn clean install而不能写mvn clean install分开(这是正确的,实际上mvn clean install确实可以连用)。但注意mvn clean和mvn site不能直接连用------必须先mvn clean再mvn site,或者配置site插件绑定到对应生命周期阶段。
五、Maven常用命令
bash
# 跳过测试进行打包
mvn clean package -DskipTests
# 指定模块构建(多模块项目)
mvn clean install -pl module-name -am
# 查看依赖树
mvn dependency:tree
# 强制更新快照依赖
mvn clean install -U
# 创建Maven项目(使用原型)
mvn archetype:generate -DgroupId=com.example -DartifactId=my-app
日常开发中最常用的5个命令:
mvn clean install:清理+编译+测试+打包+安装到本地,这是日常最频繁使用的命令mvn clean package -DskipTests:跳过测试快速打包,适合临时验证mvn dependency:tree:排查依赖冲突的利器,输出完整的依赖树mvn clean compile:仅编译,适合快速检查代码是否有语法错误mvn archetype:generate:创建项目骨架,适用于不想用IDE创建项目的场景
DskipTests与-Dmaven.test.skip的区别 :-DskipTests会编译测试代码但不执行测试;-Dmaven.test.skip=true既不编译也不执行测试代码。前者编译快但不验证测试代码本身是否有语法错误,后者完全跳过测试模块。
六、Maven插件
Maven的功能大多通过插件来实现。常用插件包括:
xml
<build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<!-- 打包可执行jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
常见插件清单:
- maven-compiler-plugin:控制Java编译版本,必须配置。如果你使用JDK 17但项目需要兼容JDK 8,就需要在这里指定source和target为8。
- maven-jar-plugin :打普通jar包。如果需要运行
java -jar直接启动,记得配置mainClass。 - maven-surefire-plugin:运行单元测试的插件。可以通过配置来控制哪些测试类执行,或者跳过测试。
- spring-boot-maven-plugin :Spring Boot专用插件,可以打Fat Jar(包含所有依赖的可执行jar),并提供
mvn spring-boot:run命令直接启动应用。 - maven-resources-plugin:处理资源文件(如properties、xml等),控制资源过滤和变量替换。
插件版本管理 :没有指定plugin版本时,Maven使用默认绑定的版本。但在生产项目中,建议显式指定插件版本,确保不同环境下构建结果一致。你可以在parent POM的<pluginManagement>中统一管理插件版本。
总结
本文从Maven的安装配置开始,详细介绍了pom.xml的结构、依赖管理、生命周期和常用命令。掌握Maven可以让你告别手动管理jar包的痛苦,将更多精力集中在业务逻辑开发上。在实际项目中,建议配合IDEA的Maven工具窗口使用,可视化地管理依赖和执行构建命令。
面试中关于Maven的高频问题:1)Maven的scope有哪些及区别?2)依赖冲突如何解决?3)Maven的生命周期阶段有哪些?4)SNAPSHOT和RELEASE的区别?5)多模块项目如何管理?建议结合本文的讲解和代码示例,用自己的话组织答案。
✅ 亮点总结
- 坐标三要素(groupId/artifactId/version)唯一标识项目,Maven仓库通过坐标定位Jar包
- 依赖范围scope(compile/provided/runtime/test)精确控制不同阶段的classpath
- 传递性依赖 自动管理,配合
<exclusions>排除冲突依赖 - 三大生命周期(clean/default/site)标准化构建流程,mvn clean install一键完成
- 阿里云镜像 和本地仓库配置,大幅提升依赖下载速度
适用场景
- 新项目搭建时通过Spring Initializr生成Maven项目,快速引入Spring Boot Starter依赖
- 多模块项目(如common/service/web分层)统一管理和构建
- 团队协作中通过parent POM统一依赖版本,避免版本冲突
扩展方向
- 学习Gradle构建工具,了解其基于Groovy/Kotlin DSL的灵活配置和增量构建优势
- 搭建私有Maven仓库(Nexus/Artifactory),管理公司内部公共组件
- 推荐阅读下一篇文章:Git版本控制基础,掌握团队协作必备技能