Maven
概念
What
- Maven是Apache软件基金会唯一维护的一款 自动化构建工具 ,专注于服务Java平台的 项目构建 和 依赖管理。
- Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。
项目构建的环节
- 清理(clean): 删除之前的编译结果,为重新编译做准备。
- 编译(compile): 将 Java 源代码编译为字节码文件到指定路径内。
- 测试(test): 执行 src/test 下的单元测试。
- 报告: 在测试完成后将以标准的格式记录和展示测试结果。
- 打包(package): 将工程封装为目标格式的文件,例如 jar、 war、pom。
- 安装(install): 将打包的结果安装到本地仓库。
- 部署(deployed): 将打包的结果部署到远程仓库或将 war 包部署到服务器上运行。
仓库的构成
配置步骤
- 下载、解压
- 配置
M2_HOME
和PATH
环境变量 - 修改本地仓库地址(~/.m2/setting.xml)
- 配置镜像
setting.xml
conf/setting.xml 相当于 maven 的全局配置,我们一般不直接需改该文件,而是复制一份到 ~/.m2
目录下进行修改。
~
表示当前用户的根目录。
配置本地仓库
本地仓库用于存放依赖包,其默认地址为: ~/.m2/repository
。因为本地仓库可能会占用大量的硬盘空间,所以我们要修改本地仓库的地址。
<localRepository>D:\dev\repository</localRepository>
配置远程仓库镜像
用于解决下载依赖过慢或无法下载依赖的问题,因为*仓库不在国内。
加载依赖的过程: 本地仓库 -> (镜像仓库 ->End) 远程仓库。如果配置了镜像仓库,远程仓库将会被屏蔽掉。
这里没有使用阿里镜像站的原因是: 在使用的过程中发现阿里的镜像站好像同步频率很低导致较新的依赖无法通过镜像站下载。
<mirrors>
<mirror>
<id>Tencent Mirror</id>
<mirrorOf>central</mirrorOf>
<name>腾讯 Maven 镜像</name>
<url>http://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
</mirror>
</mirrors>
- id: 该镜像的唯一标识符
- mirrorOf: 用于指定该镜像所代理的仓库(maven 中内置的*仓库 id 为: central)
- name: 该镜像的名称
- url: 镜像的地址
mirrorOf
mirrorOf 共有四种匹配规则:
maven 中已经内置了一个 id 为: central 的远程仓库,即*仓库,具体介绍看下文的 Super POM。
- 匹配所有仓库:
*
- 匹配所有远程仓库(匹配所有不在本机上的远程仓库):
external:*
- 匹配指定 id 的仓库(可以指定多个, 中间使用半角逗号隔开):
central
- 排除指定仓库:
!central
在 IDEA 中使用 Maven
在 Settings...
-> Build、Execution、Deployment
-> Build Tools
-> Maven
中配置 Maven home path 即可。
使用 Maven 创建 web 工程
官方介绍: Maven Webapp Archetype
web 工程结构
我们一般使用 org.apache.maven.archetypes.maven-archetype-webapp
为原型创建 web 工程,其结构如下。
project
|-- pom.xml
`-- src
`-- main
`-- webapp
|-- WEB-INF
| `-- web.xml
`-- index.jsp
使用原型创建 web 工程后目录不要进行修改,因为该原型中所使用的插件将遵行该结构进行构建,修改目录结构后将无法正常构建工程(需要重新配置插件参数信息才能正常构建,因此我们遵循该默认结构即可)。
POM 简介
官方介绍: Maven - Introduction to the POM
- POM 即 Project Object Model
- pom.xml 中包含了项目的构建信息,包括 GAV、项目依赖等。
Super POM
官方总览: Super POM for Maven 3.6.3
- Super POM 是 Maven 默认的 POM,类似于 Java 中 Object 的地位。除非特使指定,否则所有的 POM 都继承自 Super POM。
- Super POM 中定义了一些基本配置,如默认的*仓库: central、构建源文件路径和编译目标路径、打包文件名称、内置插件列表。
default pom
一个普通的 maven 工程中 pom.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>org.example</groupId>
<artifactId>my-artifact</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
指定依赖
- 我们可以在 pom.xml 中的 project 标签下使用 dependencies 指定工程中使用的依赖列表。
- 同时我们可以在 Maven *仓库 中搜索所需要的依赖及其版本。
<?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>org.example</groupId>
<artifactId>any-java-code</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--这里以 Junit 5 为例-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
依赖范围
聚合工程
聚合工程中根工程的 pom.xml 的 packaging 标签指定为 pom,且根工程不编写其他代码。
推荐文章: Maven pom.xml中的元素modules、parent、properties以及import - 青石路 - 博客园
相关内容: 父子工程直接继承依赖、父子工程间接继承依赖(依赖管理)、定义 pom 属性。
依赖的传递性
如果 A 工程依赖于 B,同时 B 又依赖 于C ,那么 A 工程中将存在 C 的依赖(即 A 中存在 C 的 jar 包),这就是依赖的传递。
传递依赖的范围
最左边一行表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递依赖范围。
依赖冲突
因为存在依赖的传递性,可能 A 工程中的多个直接依赖都又依赖于 C ,且它们的版本不一致,这就会造成依赖冲突。
当发生依赖冲突时 maven 中内置了两个规则来解决冲突问题:
- 最短路径优先: 从根工程出发到最短到达的冲突依赖将生效,其余冲突依赖不生效。
- 最先定义优先: 如果存在多个最短路径相同的冲突依赖,那么根据依赖定义顺序判断,最先定义的路径中的冲突依赖将生效,其余冲突依赖不生效。
排除依赖
有时候我们不需要根据 maven 内置的依赖冲突解决方案来解决冲突,或则我们不需要依赖传递到根工程,那么我们可以通过排除依赖来实现。
通过 exclusions 标签排除掉 junit-jupiter-engine 传递的依赖 junit-platform-engine:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
镜像站列表
个人推荐的国内镜像站,任选其一即可。
<mirror>
<id>Tencent Mirror</id>
<mirrorOf>central</mirrorOf>
<name>腾讯 Maven 镜像</name>
<url>http://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
</mirror>
<mirror>
<id>Aliyun Mirror</id>
<mirrorOf>central</mirrorOf>
<name>阿里云 Maven 镜像</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
<mirror>
<id>huawei Mirror</id>
<mirrorOf>central</mirrorOf>
<name>华为 Maven 镜像</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</mirror>
<mirror>
<id>163 Mirror</id>
<mirrorOf>central</mirrorOf>
<name>网易 Maven 镜像</name>
<url>http://mirrors.163.com/maven/repository/maven-public/</url>
</mirror>