1.使用
1.1.运行
语法:
mvn [options] [<goal(s)>] [<phase(s)]
1.2.令人迷惑的 mvn 命令
mvn compile
mvn compiler:compile
mvn install
mvn install:install
mvn install:install-file
上面的这些命令看起来有点像。mvn compile 和 mvn compiler:compile的作用也相同。但是这 2 个命令有区别。
参考 mvn 命令的语法 。mvn compile 中的 compile 指的 Maven 的 default生命周期中的 compile 阶段。对应语法中的[phase(s)]。而 mvn compiler:comile 是 Maven maven-compiler-plugin插件的一个 goal,对应语法中的 [goal(s)]。
Maven 的阶段实质上还是有插件的 goal来构成的,使用 mvn compile命令是如何就找到 maven-compiler-plugin这个插件来执行,这块实现原理现在还不太清楚。
什么时候用 mvn compiler:comile 这种格式呢?
比如我们需要设置 compile 插件的一些参数的时候,可以使用 mvn compiler:comile 这种格式,后面跟 -Dencoding=UTF-8(通过使用 -D+参数名=值)这种格式来指定具体参数。
怎么知道 compile 插件的某个 goal 有哪些参数呢?
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin -Ddetail
mvn help:describe -Dplugin=groupId:artifactId:version -Ddetail
mvn help:describe -Dplugin=插件prefix -Ddetail
help:describe本身也是 maven-help-plugin 的一个goal
使用以上命令可以打印某个插件的具体信息。Maven 提供的插件的 groupId 一般都是 org.apache.maven.plugins,artifactId 一般是 maven-****-plugin格式。
1.3.可能常用的命令
-
install 到本地仓库: Maven 在
maven-install-plugin插件中提供了install-file的目标。-
install Jar 包(非 pom 包)到本地仓库
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging> -
install pom 文件到本地仓库
mvn install:install-file -Dfile=<path-to-file> -DpomFile=<path-to-pomfile> -
maven 2.5 之后 install jar 包可以更简单。如果这个 jar 包是通过 Maven 构建的,jar 包中有
META-INF/目录且里面有这个 jar 包的 pom 文件,那么可以使用如下命令:mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -Dfile=<path-to-file>
-
-
描述某个插件的具体信息: 使用 Maven 的
maven-help-plugin插件的help:describegoalmvn help:describe -Dplugin=groupId:artifactId:version -Ddetail
内置的生命周期及其阶段按顺序是:
- clean: pre-clean,clean,post-clean
- default: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify,install, deploy
- site: pre-site, site, post-site, site-deploy
只需创建软件包并将其安装在本地存储库中,以便在其他项目中重用,只需要使用:
mvn install
如果不是在项目中或是其他情况,可能希望调用由 Maven 的一部分实现的特定任务——这被称为插件的目标:
mvn archetype:generate
mvn checkstyle:check
1.4.构建的生命周期
1.4.1.基础
Maven基于构建生命周期这一核心概念。这意味着,构建和分发特定 artifact (project) 的过程是明确定义的。
有3个内建的生命周期: default , clean 和 site。default 生命周期处理项目的部署,clean生命周期处理项目的清理,site生命周期用于将项目构建成网站。
1.4.2.构建的生命周期由阶段(Phases)组成
default 生命周期的一些阶段说明:
- validate: 验证项目是否正确以及所有必要信息是否可用
- compile: 编译项目源码
- test: 使用合适的单元测试框架测试已编译的源代码。这些测试不应要求打包或部署代码
- package: 获取编译后的代码,并将其打包为其可分发格式,如JAR。
- integration-test: 集成测试
- verify: 对集成测试结果进行检查,以确保符合质量标准。
- install: 将包放到本地仓库。
- deploy: 构建完成,将包放到远程仓库。
这些周期将按照顺序执行,以完成 default生命周期。
1.4.3.构建的阶段由插件的目标组成
然而,即使构建阶段负责构建生命周期中的特定步骤,但执行这些职责的方式也可能有所不同。这是通过声明绑定到这些构建阶段的插件目标来实现的。
一个插件目标代表一个具体的任务(比构建阶段更精细),它有助于项目的构建和管理。一个目标可以被绑定到零个或多个构建阶段。一个没有绑定到任何构建阶段的目标可以在构建生命周期之外通过直接调用来执行。执行的顺序取决于目标和构建阶段被调用的顺序。例如下面的示例,clean和package参数是构建阶段,dependency:copy-dependencies 是一个插件的目标。
mvn clean dependency:copy-dependencies package
执行上面命令后,先是 clean 阶段(包括 clean 之前的阶段)会先执行,然后执行 dependency:copy-dependencies目标,最后执行 package阶段(包括 package 之前的阶段)
此外,如果一个目标与一个或多个构建阶段绑定,那么该目标将在所有这些阶段中调用。
此外,构建阶段还可以绑定零个或多个目标。如果构建阶段没有绑定目标,则该构建阶段将不会执行。但如果它绑定了一个或多个目标,它将执行所有这些目标。
在Maven2.0.5及更高版本中,绑定到一个阶段的多个目标的执行顺序与它们在POM中声明的顺序相同
1.4.4.某些阶段通常不会从命令行调用
名字中有 pre-*,post-*,process-*的阶段不会通过命令行直接调用。这些阶段对构建进行排序,生成在构建之外没有用处的中间结果。在调用集成测试的情况下,环境可能处于挂起状态。
代码覆盖工具(如 Jacoco)和执行容器插件(如 Tomcat、 Cargo 和 Docker)将目标绑定到预集成测试阶段,以准备集成测试容器环境。这些插件还将目标绑定到后集成测试阶段,以收集覆盖率统计信息或者解除集成测试容器的运行。
Failsafe 和代码覆盖率插件将目标与integration-test和verify阶段绑定。测试和代码覆盖率报告的最终结果要在 verify阶段之后可用。如果integration-test阶段在命令行中被调用,那就不会生成报告。更糟糕的是,集成测试容器环境处于挂起状态;Tomcat webserver或Docker实例仍在运行,Maven甚至可能不会自行终止。
2.Maven 的依赖机制
2.1.传递依赖性
用户指定了某个依赖包,这个包需要的依赖 Maven 会通过依赖传递自动包含进来。所有的这些包都会在用户自己的项目中使用。
依赖传递的“深度”没有限制,只有在出现循环依赖的时候才会出现问题。
有了可传递的依赖关系,这个依赖关系的图会快速变得非常大。出于这个原因,会有一些额外的特性限制哪些依赖会被包含进来:
-
依赖调解: 这决定了当依赖遇到同一个包的多个版本时,将选择版本的包。Maven 遵循“就近原则”。也就是说,它使用依赖树中与你的项目最接近的版本。您始终可以通过在项目的 POM 中显式声明版本号来保证包的版本(也就是说自己生命冲突的包的版本是离项目最近的)。注意:如果2个依赖在依赖树中的深度相同,那么 Maven 会选择先申明的依赖。
-
就近原则: 同一个版不同版本,Maven 会选择在依赖树中离你项目最近的那个版本。
A ├── B │ └── C │ └── D 2.0 └── E └── D 1.0上面的示例中有2条依赖传递路径,A->B->C->D 2.0 和 A->E->D 1.0,Maven 在构建的时候会使用 D 1.0版本,因为它离你项目最近。您可以直接在 A 项目的 POM 文件中显示申明 D 的版本为 2.0,这样 Maven 构建的时候就会使用 D 2.0 的包。
A ├── B │ └── C │ └── D 2.0 ├── E │ └── D 1.0 │ └── D 2.0
-
-
依赖管理: 简单说 A 的依赖的依赖都会被自动包含进来。
-
依赖范围: 这允许您只包含与构建的当前阶段相适应的依赖项。下面将对此进行更详细的描述。
-
排除依赖: 比如有 A->B->C 这样的依赖路径。A 项目可以通过 “exclusion” 选项直接排除 C 依赖。
-
可选的依赖: 如果 A->B,A 项目可以通过 “optional” 将 B 项目标记为可选依赖。这样当有 C 项目依赖 A 项目的时候,只会把 A 项目自动包含进来。C 项目想要使用 B 的包就需要显示申明依赖。
尽管传递依赖可以隐式包含所需的依赖项,但最好直接显式指定源代码使用的依赖项。这一最佳实践证明了它的价值,特别是当项目的依赖更改了其依赖时。
比如有 A->B->C 这样的依赖路径,A项目也会用到 C 包的内容,但是如果 B 包突然修改或者删除了对 C 的依赖,那么 A 项目构建就会失败。
2.2.依赖范围
依赖项范围用于限制依赖的传递性,并确定依赖何时会被包含到 classpath 中。
有6种依赖范围:
- compile: 这是默认的依赖范围,构建时所有阶段都会将包自动放到 classpath 中。
- provided: 和 compile 有点像,它表示你希望 JDK 或者 容器在运行时提供包。比如,要构建一个 Java EE 的 web 项目,项目会依赖 Servlet API,这个 API 由 Java EE 提供,所以在 POM 中要定义 Servlet 的依赖为
provided范围。provided 范围的依赖,会在编译和测试阶段将 Servlet 包自动包含到 classpath 中,但在运行时不会将包放到 classpath 中。 - runtime: 这个范围的依赖表示在编译的时候不需要这个包,运行的时候需要。Maven 会在运行时和测试阶段将包放到 classpath 中。
- test: 这个范围表明,该依赖项对于应用程序的正常使用是不必要的,并且仅对于测试编译和执行阶段可用。通常这个范围的依赖用于像 JUnit 和 Mockito 这样的测试框架。
- system: 这个范围有点像
provided。但是表示用户需要自己直接提供这个包。Maven 不会在仓库里找这个包。 - import: 这个范围只支持在
<dependencymanagement>部分的 pom 类型的依赖上。它表示依赖关系将被指定 POM 中的<dependencymanagement>部分中的有效依赖关系列表替换。所以import范围的依赖是在进行替换而不是限制依赖传递。
3.原型
原型是 Maven 项目模版工具包。Maven – Introduction to Archetypes (apache.org)
4.Maven 仓库
Maven 仓库存储各类包及其依赖关系(通过 pom 文件)
有2类仓库:
- 本地: 本地仓库是远程仓库的缓存,以及没有发布到远程仓库的本地包
- 远程: 远程仓库可以使用多种协议访问,比如
file://和https://
4.1.使用仓库
从远程仓库下载:
下载动作的触发条件:项目申明了某个依赖,且该依赖不在本地仓库中(或者项目需要一个 SNAPSHOT包,远程仓库的 SNAPSHOAT包比本地的新)。默认 Maven 会去中央仓库下载。
可以在 Maven 的 setting.xml 中设置全局使用的仓库镜像以阻止 Maven 去中央仓库下载。另外项目的 POM.xml 文件中可能也会自定义仓库,但是 setting.xml 中的镜像仓库优先级更高。
4.2.离线构建
有时候构建的时候,Maven 所在机器不能连网,那就需要进行离线构建。
mvn -o package
很多插件都支持 -o选项,构建的时候不会去联网。
4.3.使用多个仓库
Maven – Guide to using Multiple Repositories (apache.org)
Maven 项目配置仓库一共有如下几种方式:
- 中央仓库,这是默认的仓库
- 镜像仓库,通过 sttings.xml 中的 settings.mirrors.mirror 配置
- 全局profile仓库,通过 settings.xml 中的 settings.repositories.repository 配置
- 项目仓库,通过 pom.xml 中的 project.repositories.repository 配置
- 项目profile仓库,通过 pom.xml 中的 project.profiles.profile.repositories.repository 配置
- 本地仓库
Maven 构建时以上仓库的使用顺序:
local_repo > settings_profile_repo > pom_profile_repo > pom_repositories > settings_mirror > central
5.配置
Apache Maven用法本身和用其构建的项目的配置存在于以下几个地方
-
MAVEN_OPTS (environment variable): 该变量包含用于启动运行Maven的JVM的参数,可用于为其提供额外选项。例如,JVM的内存设置可以用
-Xms256m -Xmx512m来定义。 -
MAVEN_ARGS (environment variable): 从Maven 4开始,该变量包含在CLI参数之前传递给Maven的参数。例如,选项和目标可以用值
-B -V checkstyle:checkstyle来定义。 -
settings.xml (file): 位于
USER_HOME/.m2的配置文件是所有 maven 项目都可以使用的配置 -
.mvn (directory): 位于项目的顶级目录中,文件
maven.config、jvm.config和extensions.xml包含运行 Maven 的项目特定配置。这个目录应该是项目的一部分,需要被版本管理工具管理 -
.mvn/extensions.xml (file): 旧的方法(直到Maven 3.2.5)如果有自己的 maven 扩展,需要手动将其放入
{MAVEN_HOME}/lib/ext目录。这意味着需要改动 maven 的安装结构。结果是,每个喜欢使用这个扩展的人都需要改变它的安装,这使得开发人员更加不方便。另外一种使用自定义扩展的方式是使用命令行mvn -Dmaven.ext.class.path=extension.jar。这有一个缺点,每次使用 maven 构建项目的时候都需要使用这个选项,也不是很方便。
现在可以使用更像 maven 的方式来实现。只需要在${maven.projectBasedir}/.mvn/extensions.xml配置文件中进行如下定义:<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd"> <extension> <groupId/> <artifactId/> <version/> </extension> </extensions> -
.mvn/maven.config (file): 很难定义一组通用的选项来调用maven命令行。从 Maven 3.3.1+开始,可以将选项放在
${maven.projectBasedir}/.mvn/maven.config配置文件中。比如-T3 -U --fail-at-end。使用 mvn 的时候只需要使用mvn clean package来替代mvn -T3 -U --fail-at-end clean package -
./mvn/jvm.config (file): 从 Maven 3.3.1+ 开始,JVM 选项可以放在
${maven.projectBasedir}/.mvn/jvm.config配置文件中。这样的话就可以根据项目来调整 Maven 的 JVM 设置。所以就不再需要MAVEN_OPTS和.mavenrc文件。示例:-Xmx2048m -Xms1024m -XX:MaxPermSize=512m -Djava.awt.headless=true
5.1.POM
pom: 项目对象模型。POM 格式说明
pom 的 xml 文件对于大部分项目来说包含了很多默认值。比如项目构建的输出目录是 target,源码目录是 src/main/java,测试源码目录是 src/test/java
在 pom.xml中 <packaging/>默认的打包方式是 jar。也可以是 pom、jar、maven-plugin、ejb、war、ear、rar。
5.1.1.Super POM
Super POM 是 Maven 的默认 pom,所有的 pom 都继承 Super POM 除非显示设置。Maven Model Builder – Super POM (apache.org)
5.1.2.父子 POM 中的元素会被合并
POM中合并的元素如下(在父子 maven 项目中,pom 中的元素会被合并):
- dependencies
- developers and contributors
- plugin lists (including reports)
- plugin executions with matching ids
- plugin configuration
- resources
5.1.3.POM 中可用的变量
这些变量以 project.或者pom.作为前缀,没有前缀的变量建议不再使用.
| 变量名 | 含义 |
|---|---|
project.basedir | 当前项目所在的目录 |
project.baseUri | 当前项目所在的目录,表示为URI。从Maven 2.1.0开始 |
maven.build.timestamp | 表示构建开始时间(UTC)的时间戳. |
5.2.settings.xml 配置
5.2.1.格式说明
有 2 个地方有 settings.xml 配置文件。
${maven.home}/conf/settings.xml: 全局配置文件${user.home}/.m2/settings.xml: 用户配置文件。
如果以上 2 个配置文件都存在,那么全局配置文件的内容会被合并到用户配置文件中。
settings.xml 配置文件概览:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>
5.2.2.镜像仓库的配置
Maven – Guide to Mirror Settings (apache.org)
在 ${user.home}/.m2/settings.xml 中进行配置。配置文件如下示例:
<settings>
...
<mirrors>
<mirror>
<id>other-mirror</id>
<name>Other Mirror Repository</name>
<url>https://other-mirror.repo.other-company.com/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
...
</settings>
mirrorOf 标签中的的 central 默认表示中央仓库。mirrorof 标签和值之间不能有空格。
mirrorof 标签可以有以下这些配置:
*: 表示镜像所有的仓库external:*: 匹配除了使用本地主机或基于文件的仓库之外的所有仓库。external:http:*: 从 Maven 3.8.0 开始,表示使用 HTTP 匹配所有存储库,但使用本地主机的存储库除外。*,!repo1: 表示除了 repo1 仓库外的其他仓库。
5.2.3.发布包和下载包的配置
deploy 自己的包可以在 distributionManagement 中进行配置,但是不能在其中配置用户名、密码和其他安全选项。所以可以在 setting.xml 中进行配置,示例如下:
<settings>
.
.
<servers>
<server>
<id>repo1</id>
<username>repouser</username>
<!-- other optional elements:
<password>my_login_password</password>
<privateKey>/path/to/identity</privateKey> (default is ~/.ssh/id_dsa)
<passphrase>my_key_passphrase</passphrase>
-->
</server>
</servers>
.
.
</settings>
5.2.4.配置代理
Maven – Guide to using proxies (apache.org)
可以对 Maven 部分或全部的 http 请求配置代理。示例如下:
<settings>
.
.
<proxies>
<proxy>
<id>example-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>somepassword</password>
<nonProxyHosts>www.google.com|*.example.com</nonProxyHosts>
</proxy>
</proxies>
.
.
</settings>
nonProxyHosts标签可以使用通配符,不同 host 之间使用 |分割
6.插件
maven 本质上是一个插件执行框架,所有的工作通过插件来完成。
常见插件一句话介绍:
| 插件 | prefix | 描述 |
|---|---|---|
| maven-clean-plugin | clean | 构建后清理 |
| maven-compiler-plugin | compiler | 编译 java 源代码 |
| maven-deploy-plugin | deploy | 发布包到远程仓库 |
| maven-surefire-plugin | surefire | 运行 Junit 测试 |
| maven-install-plugin | install | 将包安装到本地仓库 |
| maven-resources-plugin | resources | 将资源(resource 目录)复制到编译后的目录,以便包含到 JAR 中 |
| maven-site-plugin | site | 用当前项目生成一个网站 |
| maven-verifier-plugin | verifier | 有用的集成测试 - 验证某些条件的存在 |
| maven-jar-pluign、maven-war-plugin | jar、war | 打 jar 、war 包 |
| maven-shade-plugin | shade | 打 Uber-jar ,包括依赖也会打到包中 |
6.1.Maven 工具
默认情况下,Maven 提供了各种各样的工具。工具实际上也是一种插件。
常用工具一句话介绍:
| 插件 | prefix | 描述 |
|---|---|---|
| maven-dependency-plugin | dependency | 依赖操作(复制、解压缩)和分析 |
| maven-help-plugin | help | 获取当前项目工作环境信息,获取插件详情 |
6.2.配置插件
Maven – Guide to Configuring Plug-ins (apache.org)
6.3.插件前缀解析介绍
Maven – Introduction to Plugin Prefix Resolution (apache.org)
本文详细介绍了 Maven 的使用,包括运行命令、构建生命周期的各个阶段、插件目标及其区别,以及依赖管理和仓库使用。重点讨论了 Maven 的默认生命周期,如 validate、compile、install 等阶段,还解释了依赖的传递性、依赖范围和排除机制。此外,还涵盖了 Maven 的配置,如 POM 文件和 settings.xml 文件的作用,以及如何配置镜像仓库和代理。
568

被折叠的 条评论
为什么被折叠?



