Maven 手册

什么是 Maven

Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.

Apache Maven 本质是一个软件项目管理和理解工具,它提供了一种项目管理的方法,涵盖了了项目管理中常见的阶段:

  • Builds
  • Documentation
  • Reporting
  • Dependencies
  • SCMs
  • Releases
  • Distribution

安装

官网下载安装包。

基础环境

Maven 依赖 Java 环境,所以要先确保已经正确安装 JDK

通过 java -version 命令来查看是否正确安装了 JDK

1
2
3
4
PS C:\Users\fuyon> java -version
java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)

Windows

解压

将下载好的安装包 apache-maven-3.6.1-bin.zip 解压至 C:\(或其他路径)。

配置环境变量

打开 控制面板 > 系统和安全 > 系统 > 高级系统设置 > 环境变量 > 系统变量

  1. 新建一个变量名M2_HOME,变量值为 C:\apache-maven-3.6.1 (即 Maven 的安装路径)。
  2. 选中系统变量中的 Path,并新增 %M2_HOME%\bin\

验证

打开终端,输入 mvn --version,输出

1
2
3
4
5
6
7
PS C:\Users\fuyongde> mvn --version
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d; 2017-10-18T15:58:13+08:00)
Maven home: C:\apache-maven-3.5.2\bin\..
Java version: 1.8.0_162, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_162\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

表示安装成功

Linux & Mac OS

你都用这操作系统了,那肯定会安装吧 🤣。

使用

快速开始

Maven 提供了丰富的模板,以供我们快速创建一个工程。其命令如下:

1
2
3
4
5
mvn archetype:generate
-DgroupId=com.demo
-DartifactId=hello-maven
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

其中各个参数的含义:

  • -DgroupId:组织的唯一标识符
  • -DartifactId:项目的唯一标识符
  • -DarchetypeArtifactId:指定 ArchetypeId,常见的选项 maven-archetype-quickstart (Java project)、maven-archetype-webapp (web project)
  • -DinteractiveMode:是否使用交互模式

目录结构

不同的模板创建出来的项目目录可能会有差异,常见的 Maven 目录结构如下:

1
2
3
4
5
6
7
8
9
├── src
│ ├── main
│ │ ├── java # 源码目录
│ │ └── resources # 资源目录
│ └── test
│ ├── java # 单元测试源码目录
│ └── resources # 单元测试资源目录
├── target # 项目编译输出的目录
├── pom.xml

Maven 生命周期

Maven 默认的生命周期包括:

  1. validate: 验证项目是否正确,并提供所有必要的信息
  2. compile: 编译源码
  3. test: 使用合适的单元测试框架测试编译的源代码,单元测试的代码并不会被打包。
  4. package: 获取已编译的代码并将其打包为可分发的格式,例如 JAR。
  5. integration-test: 如有必要,将程序包处理并部署到可以运行集成测试的环境中
  6. verify: 验证打包文件是否有效并符合质量标准
  7. install: 将项目打包安装到本地存储库中,以便在本地用作其他项目的依赖项
  8. deploy: 将项目打包并推送到 Maven 私服或中央仓库

此外还有两个生命周期的阶段

  • clean: 清除之前构建
  • site: 为此项目生成站点文档

POM

1
POM stands for "Project Object Model". It is an XML representation of a Maven project held in a file named pom.xml.

POM 表示“项目对象模型”,在 Maven 项目中以一个 pom.xml 文件的形式存在。

最基本的构成

一个 pom.xml 最基本的构成如下:

1
2
3
4
5
6
7
8
9
10
<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>org.codehaus.mojo</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
</project>

其中

  • modelVersionMaven2 & 3只支持 4.0.0
  • groupId:组织的唯一标识符
  • artifactId:项目的唯一标识符
  • version:版本号

packaging

pom.xml 中可以添加 <packaging>war</packaging> 来标识项目最终的打包格式,缺省值为:jar,可选值:pom, jar, maven-plugin, ejb, war, ear, rar

1
2
3
4
5
6
7
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">
...
<packaging>war</packaging>
...
</project>

POM Relationships(重点)

Maven 的一个强大的功能,就是它处理项目之间关系的能力,包括了:依赖项管理、继承和聚合。

依赖

依赖管理是 POM 的灵魂,大部分的项目都会依赖于其他项目来构建以及正确的运行。通过依赖管理,我们可以方便的下载、引入所需的其他依赖项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<type>jar</type>
<scope>test</scope>
<optional>true</optional>
</dependency>
...
</dependencies>
...
</project>
groupId、artifactId

表示依赖项的坐标。由于依赖项都是由 Maven 坐标,意味着我们的项目只能依赖于同样是 Maven 管理的其他项目。但是很多时候,项目可能会依赖一些具有闭源许可的 jar,这些 jar 并不存在于中央仓库,有三种办法可以解决这个问题。

  • 使用 install 插件在本地安装依赖项,这是最简单也是最推荐的方式。例如:
1
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
  • 将依赖部署到私服

  • 将依赖的 scope 设置为 system 并且定义 systemPath,强烈不推荐这种方式。

version

表示依赖的版本,关于 version 语法如下:

  • 1.0:若匹配到了 1.0 版本,则使用 1.0 版本
  • [1.0]: 强制配依赖项的 1.0 版本
  • (,1.0]: x <= 1.0
  • [1.2,1.3]: 1.2 <= x <= 1.3
  • [1.0,2.0): 1.0 <= x < 2.0
  • [1.5,): x >= 1.5
  • (,1.0],[1.2,): x <= 1.0 or x >= 1.2,多个版本集合的情况以逗号分隔
  • (,1.1),(1.1,): 排除 1.1 版本

此外,version 的不同写发也存在优先级,详情可参考官网

type

依赖项的类型,缺省值是 jar。除此之外还有ejb-clienttest-jar,但都不常用

scope

依赖项作用的范围以及如何限制依赖项的传递性。共五个范围值可选:

  • compile:缺省值即为 compile,表示依赖项参与项目的编译、测试、运行阶段,项目打包时,也会打进去。
  • provided:依赖项参与项目的编译、测试阶段,与 compile 不同的是不会打包进项目中,但是期望 JDK容器或使用者会提供该依赖项。
  • runtime:编译时不需要该依赖项,但是执行时需要。
  • test:项目不需要该依赖项,并且仅适用于单元测试的编译和执行阶段,不具有传递性。
  • system:使用上与 provided 相同,不同之处在于该依赖不从 Maven 仓库中提取,而是从本地文件系统中提取,其会参照 systemPath 的属性进行提取依赖。
systemPath

仅在 scopesystem 时使用,必须指定本地的绝对路径,且必须保证文件存在。例如:

1
2
3
4
5
6
7
<dependency>
<groupid>org.hamcrest</groupid>
<artifactid>hamcrest-core</artifactid>
<version>1.5</version>
<scope>system</scope>
<systempath>${basedir}/WebContent/WEB-INF/lib/hamcrest-core-1.3.jar</systempath>
</dependency>
optional

标记依赖项是否可选,缺省值为 false

若项目 A 依赖项目 B,项目 B 依赖项目 Coptionaltrue,此时若 项目 A 没有显式的依赖 C,则项目 A 不依赖 C,且打包过程中,不会将 C 打包进来。例如 fastjson 依赖了 spring-webmvc,若使用者在开发的项目依赖了 fastjson并且没有依赖 spring-webmvc,则此项目是不依赖 spring-webmvc

排除依赖项

由于依赖的传播的特性,我们可以排除一个依赖项中我们不需要的依赖。

排除部分依赖项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
排除所有依赖项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<version>3.1.0</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>

继承

在继承关系中,父工程的 packaging 类型必须为 pom,父工程的大多数属性会被子工程继承,包括

  • groupId
  • version
  • description
  • url
  • inceptionYear
  • organization
  • licenses
  • developers
  • contributors
  • mailingLists
  • scm
  • issueManagement
  • ciManagement
  • properties
  • dependencyManagement
  • dependencies
  • repositories
  • pluginRepositories
  • build
    • plugin executions with matching ids
    • plugin configuration
    • etc.
  • reporting
  • profiles

不会被继承的属性包括:

  • artifactId
  • name
  • prerequisites

看一个列子

父工程:

1
2
3
4
5
6
7
8
9
10
11
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<packaging>pom</packaging>
</project>

子工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<relativePath>../my-parent</relativePath>
</parent>

<artifactId>my-project</artifactId>
</project>

其中 relativePath 不是必需的,但如果指定了,该路径则会作为搜索父工程的首选项。

Dependency Management

在存在多个项目的情况下,在在父项目中定义 dependencyManagement 来帮住管理所有子项目的依赖项。如果在父项目中的 dependencyManagement 标签下定义了某个依赖项的信息,则在子项目中只需要填写该依赖项的 groupIdartifactId 即可。好处是可以避免不同的子项目,引入不同版本的依赖项。

聚合

聚合可以将不同的模块,聚合在一起进行构建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<packaging>pom</packaging>

<modules>
<module>my-project</module>
<module>another-project</module>
<module>third-project/pom-example.xml</module>
</modules>
</project>

未完待续…