Maven 是一个强大的 Java 项目管理和构建工具,它简化了项目的构建过程,管理项目的依赖,并提供统一的项目结构和生命周期管理。主要功能包括:
- 依赖管理:自动下载和管理项目所需的第三方库(如JAR文件)
- 项目构建:编译源代码、运行测试、打包项目、生成文档等
- 项目管理:统一的项目结构和配置,简化团队协作
Google 推出的 Gradle 是 Maven 主要竞对,支持使用 Groovy 或 Kotlin DSL 编写构建脚本,非常灵活。同时 Gradle 支持差量处理、任务并行等特性,使其拥有更高的性能
Maven 与前端工具对比
如果熟悉前端工程化工具,可以将 Maven 看作 Java 生态中的类似工具:
| 前端工具 | Maven |
|---|---|
| npm + webpack | Maven |
| package.json | pom.xml |
| node_modules | Local Repository |
| registry | Central Repository |
- pom.xml:类似于前端的 package.json,用于定义项目依赖、插件和构建配置
- Local Repository:本地存储已经下载的依赖包,类似于 node_modules
- Central Repository:Maven的中央仓库,用于存储和下载各种Java依赖,类似于 npm 的 registry
Maven 的核心概念
项目对象模型 POM
POM(Project Object Model) 是Maven项目的核心,通过 pom.xml 文件进行配置。POM文件定义了项目的结构、依赖、插件、构建目标等。
<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-web-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- 依赖项在此添加 -->
</dependencies>
<build>
<plugins>
<!-- 插件在此添加 -->
</plugins>
</build>
</project>
依赖管理
Maven通过在POM文件中定义依赖来自动管理第三方库,Maven 会从中央仓库或指定的仓库下载这些依赖,并将其添加到项目中
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.0</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Java 可复用的软件包发布为 JAR(Java Archive)格式,在 Maven 中管理的 JAR 其唯一标识由三个部分组成
- groupId:类似 Java 的包名,通常是公司或者组织的名称
- artifactId:类似 Java 类名,通常是项目名称
- version:版本号,一般使用 x.y.z 格式
在 Node.js 一般会用 x.z.z-beta.3 这种形式来表示、指定安装开发中的版本,Java 中则使用 z.y.z-SNAPSHOT 的方式,SNAPSHOT 可以不修改版本号反复修改、发布
Maven 不会对 SNAPSHOT 版本包缓存,每次构建都会重新下载。部分团队会利用此特性来配置类似安全相关的,这类需要使用最新版本的 JAR 包
在 central.sonatype.dev/ 上可以方便搜索 Maven 中心仓库的包信息及引用方式
Repositories
Maven 使用仓库来存储和获取依赖,主要有:
- 中央仓库(Central Repository) :默认的官方仓库,包含了大量的开源Java依赖
- 本地仓库(Local Repository) :本机上的缓存位置,默认位于
~/.m2/repository - 远程仓库(Remote Repositories) :公司内部或第三方的仓库,用于存储特定的依赖
安装 Maven
-
下载 Maven:访问 Maven 官方下载页,下载最新版本的二进制压缩包(例如
apache-maven-3.8.6-bin.zip或apache-maven-3.8.6-bin.tar.gz) -
解压缩:将下载的压缩包解压到你选择的目录(例如
C:\Program Files\Apache\Maven或/usr/local/apache-maven)。 -
配置环境变量:将 Maven 的
bin目录添加到系统的PATH环境变量中。-
Windows:
- 右键“此电脑” > “属性” > “高级系统设置” > “环境变量”。
- 在“系统变量”中找到
Path,点击“编辑”,添加C:\Program Files\Apache\Maven\apache-maven-3.8.6\bin。
-
macOS/Linux:
- 编辑
~/.bash_profile,~/.zshrc或~/.bashrc文件,添加export PATH=/usr/local/apache-maven/apache-maven-3.8.6/bin:$PATH
- 编辑
-
运行命令 mvn --version验证
Maven 中央仓库下载可能会比较慢,修改 maven 安装目录/conf/setting.xml,在 mirroes 节点添加以下内容,可以切换为阿里云镜像
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
Maven 项目结构
使用 IntelliJ IDEA 可以很方便创建一个 Maven 项目
maven-project
├── pom.xml // 项目描述文件,类似 Node.js 项目的 package.json
├── src
│ ├── main
│ │ ├── java // Java 源码
│ │ └── resources // 资源文件
│ └── test
│ ├── java
│ └── resources
└── target // 编译、打包生成的文件
在 pom.xml 配置项目依赖
在项目 pom.xml dependencies 节点中添加 dependency 节点,设置 groupId、artifactId、version 可以添加依赖,在 IntelliJ IDEA 中使用 Maven 工具可以快速把依赖下载到项目 External Libraries
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-web-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.0</version>
</dependency>
<!-- JUnit 5 for Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
<!-- 其他依赖项 -->
</dependencies>
<!-- 构建插件可以在此添加 -->
</project>
有时候会发现部分模块定义版本号为 999-not-exist,主要是为了加载一个 Maven 中不存在的版本号,从而强制排除项目对该包的依赖
使用 scope 指定 JAR 使用范围
可以注意到有些包在配置依赖时候会添加scope
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
Maven 构建生命周期是一个有序的阶段序列,这些阶段会依次执行,以完成项目的构建和部署等操作。主要包括以下几个重要阶段:
-
清理(Clean) :删除之前构建产生的输出文件,确保构建环境的干净
- 命令:
mvn clean - 主要操作:删除
target目录及其内容,该目录通常包含编译的类文件、打包文件、测试报告等。
- 命令:
-
编译(Compile) :将源代码编译为字节码
- 命令:
mvn compile - 主要操作:将
src/main/java目录下的 Java 源代码编译为字节码文件,并存储在target/classes目录下。
- 命令:
-
测试(Test) :运行单元测试,确保代码的正确性
- 命令:
mvn test - 主要操作:
- 编译
src/test/java中的测试代码。 - 使用 JUnit 或 TestNG 等测试框架运行测试。
- 测试结果存储在
target/surefire-reports目录下。
- 编译
- 命令:
-
打包(Package) :将编译后的类文件和资源文件打包成可分发的文件格式
-
命令:
mvn package -
主要操作:
- 对于 Java 项目,将
target/classes目录下的文件打包成.jar文件。 - 对于 Web 项目,可能打包成
.war文件。 - 对于 Spring Boot 项目,使用 Spring Boot Maven 插件可将项目打包成可执行的
.jar或.war文件。
- 对于 Java 项目,将
-
-
安装(Install) :将打包好的文件安装到本地 Maven 仓库中,以便其它项目使用
- 命令:
mvn install - 主要操作:将
target目录下生成的.jar或.war文件复制到本地 Maven 仓库(通常位于用户的~/.m2/repository目录)。
- 命令:
-
部署(Deploy) :将打包好的文件部署到远程 Maven 仓库,以供团队或组织内的其他成员使用
- 命令:
mvn deploy - 主要操作:将项目的构建产物上传到远程 Maven 仓库,需要在
pom.xml中配置远程仓库的信息。
- 命令:
有些命令执行多个阶段
- mvn package: 会依次执行 compile、test、package 阶段
- mvn install:会依次执行 compile、test、package、install 阶段
- mvn verify:会执行 validate、compile、test、package、integration-test、verify 阶段
不同 jar 在项目不同阶段起作用, 可以指定包生效的阶段
| scope | 说明 | 示例 |
|---|---|---|
| compile | 默认值,依赖包会参与项目的编译、测试、打包、运行阶段 | log4j |
| provided | 和 compile 类似,因为内容由 JDK 或者服务器等提供,不参与打包 | servlet-api |
| runtime | 不需要参与编译,但运行、打包时需要,一般是因为代码中仅仅使用了接口 | mysql |
| test | 仅在测试阶段被使用,包括测试代码的编译、执行 | junit |
| system | 和 provided 类似,但依赖不从 maven 加载,而是从系统本地获取 | |
| import | 表示从其它 pom 导入依赖,相当于引用,解决项目只能设置一个父项目的限制问题 |
上文中 junit 的配置,表示该 jar 只在测试阶段被使用