Maven基础知识(4)- Maven 插件、Maven Archetype (原型/模板)、Maven SNAPSHOT (快照)
1. Maven 插件
Maven 实际上是一个依赖插件执行的框架,它执行的每个任务实际上都由插件完成的。Maven 的核心发布包中并不包含任何 Maven 插件,它们以独立构件的形式存在,只有在 Maven 需要使用某个插件时,才会去仓库中下载。
Maven 提供了如下 2 种类型的插件。
插件类型 | 描述 |
Build plugins | 在项目构建过程中执行,在 pom.xml 中的 build 元素中配置 |
Reporting plugins | 在网站生成过程中执行,在 pom.xml 中的 reporting 元素中配置 |
下面是一些常用插件的列表:
插件 | 描述 |
clean | 构建之后清理目标文件。删除目标目录。 |
compiler | 编译 Java 源文件。 |
surefile | 运行 JUnit 单元测试。创建测试报告。 |
jar | 从当前工程中构建 JAR 文件。 |
war | 从当前工程中构建 WAR 文件。 |
javadoc | 为工程生成 Javadoc。 |
antrun | 从构建过程的任意一个阶段中运行一个 ant 任务的集合。 |
1) 插件目标
对于 Maven 插件而言,为了提高代码的复用性,通常一个 Maven 插件能够实现多个功能,每一个功能都是一个插件目标,即 Maven 插件是插件目标的集合。我们可以把插件理解为一个类,而插件目标是类中的方法,调用插件目标就能实现对应的功能。
插件目标的通用写法如下:
[插件名]:[插件目标名]
例如,maven-compiler-plugin 插件的 compile 目标的通用写法如下:
maven-compiler-plugin:compile
使用 Maven 命令执行插件的目标,语法如下:
mvn [插件名]:[目标名]
例如,调用 maven-compiler-plugin 插件的 compile 目标,命令如下:
mvn compiler:compile
2) 插件绑定
为了完成某个具体的构建任务,Maven 生命周期的阶段需要和 Maven 插件的目标相互绑定。例如,代码编译任务对应了default 生命周期的 compile 阶段,而 maven-compiler-plugin 插件的 compile 目标能够完成这个任务,因此将它们进行绑定就能达到代码编译的目的。
(1) 内置绑定
Maven 默认为一些核心的生命周期阶段绑定了插件目标,当用户调用这些阶段时,对应的插件目标就会自动执行相应的任务。
生命周期/阶段 | 插件目标 | 执行的任务 |
clean/clean | maven-clean-plugin:clean | 清理 Maven 的输出目录 |
site/site | maven-site-plugin:site | 生成项目站点 |
site/site-deploy | maven-site-plugin:deploy | 部署项目站点 |
default/process-resources | maven-resources-plugin:resources | 复制资源文件到输出目录 |
default/compile | maven-compiler-plugin:compile | 编译代码到输出目录 |
default/process-test-resources | maven-resources-plugin:testResources | 复制测试资源文件到测试输出目录 |
default/test-compile | maven-compiler-plugin:testCompile | 编译测试代码到测试输出目录 |
default/test | maven-surefire-plugin:test | 执行测试用例 |
default/package | maven-jar-plugin:jar/maven-jar-plugin:war | 创建项目 jar/war 包 |
default/install | maven-install-plugin:install | 将项目输出的包文件安装到本地仓库 |
default/deploy | maven-deploy-plugin:deploy | 将项目输出的包文件部署到到远程仓库 |
上表中,只列出了各生命周期中绑定了插件目标的阶段,部分生命周期还有很多其他的阶段,但这些阶段默认没有绑定任何插件目标,因此它们也没有任何实际的行为。
以直接在执行 Maven 命令看到该构建过程包含了哪些插件目标。例如,在 Maven 项目中执行 mvn clean install 命令,能看到如下输出,图中标记的部分就是执行此命令时所调用的插件目标。
(2) 自定义绑定
除了内置绑定之外,用户也可以自己选择将某个插件目标绑定到 Maven 生命周期的某个阶段上,这种绑定方式就是自定义绑定。自定义绑定能够让 Maven 在构建过程中执行更多更丰富的任务。
示例,将 maven-antrun-plugin:run 目标绑定到 clean 阶段上,并使用该插件输出自定义文本信息:
1 <build> 2 ... 3 <plugins> 4 <!-- 绑定插件 maven-antrun-plugin --> 5 <plugin> 6 <groupId>org.apache.maven.plugins</groupId> 7 <artifactId>maven-antrun-plugin</artifactId> 8 <version>1.8</version> 9 <executions> 10 <execution> 11 <!-- 自定义 id --> 12 <id>com.example-clean</id> 13 <!-- 插件目标绑定的构建阶段 --> 14 <phase>clean</phase> 15 <!-- 插件目标 --> 16 <goals> 17 <goal>run</goal> 18 </goals> 19 <!-- 配置 --> 20 <configuration> 21 <!-- 执行的任务 --> 22 <tasks> 23 <echo>Maven clean lifecycle -> clean: 自定义输出信息</echo> 24 </tasks> 25 </configuration> 26 </execution> 27 </executions> 28 </plugin> 29 </plugins> 30 </build>
以上配置中除了插件的坐标信息之外,还通过 executions 元素定义了一些执行配置。executions 下的每一个 executin 子元素都可以用来配置执行一个任务。
execution 下各个元素含义如下:
a) id:任务的唯一标识。
b) phase:插件目标需要绑定的生命周期阶段。
c) goals:用于指定一组插件目标,其子元素 goal 用于指定一个插件目标。
d) configuration:该任务的配置,其子元素 tasks 用于指定该插件目标执行的任务。
当插件目标绑定到生命周期的不同阶段时,其执行顺序由生命周期阶段的先后顺序决定。如果多个目标绑定到同一个生命周期阶段,其执行顺序与插件声明顺序一致,先声明的先执行,后声明的后执行。
2. Maven Archetype (原型/模板)
Archetype 是 Maven 项目的模板工具包,它定义了 Maven 项目的基本架构。Archetype 为开发人员提供了数千种创建 Maven 项目的模板,Maven 通过这些模板可以帮助用户快速的生成项目的目录结构以及 POM 文件。
Maven Archetype 由下面 5 个模块组成:
(1) maven-archetype-plugin:Archetype 插件。
(2) archetype-packaging:用于描述 Archetype 的生命周期与构建项目软件包。
(3) archetype-models:用于描述类与引用。
(4) archetype-common:核心类。
(5) archetype-testing:用于测试 Maven Archetype 的内部组件。
1) maven-archetype-plugin 插件
Maven 的所有功能都是通过插件实现的,Archetype 也不例外,它是由一个名为 maven-archetype-plugin 的插件实现的,该插件提供了 ArcheType 的所有功能。
虽然 ArcheType 只是一个插件,但其应用范围十分的广泛,几乎所有的主流 IDE(例如 Eclipse、NetBeans 和 IntelliJ IDEA)都在集成 Maven 时着重继承了 Archetype 特性,以方便用户快速的创建 Maven 项目。
执行以下命令可以帮助用户快速的创建 Maven 项目.
mvn archetype:generate
执行以上命令时,Maven 会输出一个 ArcheType 列表,每个ArcheType 前面都对应一个编号,可以根据不同的需求选择合适的 Archetype。
Archetype 只是一个模板,为了保持模板的通用性,它的很多重要的信息都是可配置的,在用户选择了 Archetype 后,还需要提供一些关于项目的基本参数,主要包括以下参数:
groupId
artifactId
version
package
在输入以上参数后,Archetype 插件就能够为用户生成项目的基本目录结构和 POM 文件了。
2) 示例
打开 cmd 命令行窗口,进入 D:\Workshop\maven 目录,执行如下命令:
D:\Workshop\maven> mvn archetype:generate
命令执行后,显示 Archetype 列表:
... Choose archetype: 1: internal -> org.apache.maven.archetypes:maven-archetype-archetype (An archetype which contains a sample archetype.) 2: internal -> org.apache.maven.archetypes:maven-archetype-j2ee-simple (An archetype which contains a simplifed sample J2EE application.) 3: internal -> org.apache.maven.archetypes:maven-archetype-plugin (An archetype which contains a sample Maven plugin.) 4: internal -> org.apache.maven.archetypes:maven-archetype-plugin-site (An archetype which contains a sample Maven plugin site. This archetype can be layered upon an existing Maven plugin project.) 5: internal -> org.apache.maven.archetypes:maven-archetype-portlet (An archetype which contains a sample JSR-268 Portlet.) 6: internal -> org.apache.maven.archetypes:maven-archetype-profiles () 7: internal -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.) 8: internal -> org.apache.maven.archetypes:maven-archetype-site (An archetype which contains a sample Maven site which demonstrates some of the supported document types like APT, XDoc, and FML and demonstrates how to i18n your site. This archetype can be layered upon an existing Maven project.) 9: internal -> org.apache.maven.archetypes:maven-archetype-site-simple (An archetype which contains a sample Maven site.) 10: internal -> org.apache.maven.archetypes:maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 7:
默认 7 代表 maven-archetype-quickstart,直接按回车键:
Define value for property 'groupId':
输入 com.example,按回车键:
Define value for property 'artifactId':
输入 MavenDemo03,按回车键:
Define value for property 'version' 1.0-SNAPSHOT: :
直接按回车键:
Define value for property 'package' com.example: :
直接按回车键:
Confirm properties configuration:
groupId: com.example
artifactId: MavenDemo03
version: 1.0-SNAPSHOT
package: com.example
Y: :
直接按回车键:
[INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.1 [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: basedir, Value: D:\Workshop\maven [INFO] Parameter: package, Value: com.example [INFO] Parameter: groupId, Value: com.example [INFO] Parameter: artifactId, Value: MavenDemo03 [INFO] Parameter: packageName, Value: com.example [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] project created from Old (1.x) Archetype in dir: D:\Workshop\maven\MavenDemo03 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 20:30 min [INFO] Finished at: 2022-06-05T20:52:01+08:00 [INFO] ------------------------------------------------------------------------
项目 MavenDemo03 创建成功。
3. Maven SNAPSHOT (快照)
Maven 项目初次构建时,会自动从远程仓库搜索依赖项,并将其下载到本地仓库中。当项目再进行构建时,会直接从本地仓库搜索依赖项并引用,而不会再次向远程仓库获取。这样的设计能够避免项目每次构建时都去远程仓库下载依赖,减轻了网络带宽的压力,但也带来了问题。
大型的应用软件通常由多个功能模块组成,这些模块一般分别于不同的团队负责开发。假设有两个团队,他们分别负责项目中的 app-ui(前端) 和 data-service(数据服务) 两个模块,且 app-ui 需要依赖 data-service 项目作为数据服务来源。
基于以上假设,若 data-service 团队正在进行快节奏的 bug 修复及功能增强,会在短时间内高频率地更新代码以及发布版本。就会出现以下情况:
(1) data-service 团队每次发布新版本更新代码时,都应该通知 app-ui 团队。
(2) app-ui 团队则需要定期更新其 pom.xml 以获得最新的版本。
这样会影响开发效率,甚至会影响项目的验收及投产。要解决这个问题,其实很简单,那就是使用 SNAPSHOT(快照)版本。
1) SNAPSHOT 是什么
SNAPSHOT(快照)是一种特殊的版本,它表示当前开发进度的副本。与常规版本不同,快照版本的构件在发布时,Maven 会自动为它打上一个时间戳,有了这个时间戳后,当依赖该构件的项目进行构建时,Maven 就能从仓库中找到最新的 SNAPSHOT 版本文件。
定义一个组件或模块为快照版本,只需要在其 pom.xml 中版本号(version 元素的值)后加上 -SNAPSHOT 即可,例如:
<groupId>com.example</groupId>
<artifactId>MavenDemo01</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
要解决上面的问题,现在就十分简单了:data-servcie 团队每次更新代码都使用快照版本发布到仓库中,app-ui 团队则引用快照版本的依赖,这样 app-ui 不再需要重复修改 pom.xml 中的配置,每次构建时都会自动从仓库中获取最新的构件。
默认情况下对于快照本本的构件,Maven 会每天从仓库中获取一次更新,用户也可以在任何 Maven 命令中使用 -U 参数强制 Maven 检查更新。命令如下:
mvn clean compile -U
或
mvn clean package -U
2) SNAPSHOT 版本 VS RELEASE 版本
Maven 仓库分为两种,Snapshot 快照仓库和 Release 发行仓库。Snapshot 快照仓库用于保存开发过程中的不稳定 SNAPSHOT 版本,Release 发行仓库则用来保存稳定的 RELEASE 版本。
Maven 会根据模块的版本号(pom.xml 文件中的 version 元素)中是否带有 -SNAPSHOT 来判断是 SNAPSHOT 版本还是正式 RELEASE 版本。带有 -SNAPSHOT 是 SNAPSHOT(快照)版本,不带 -SNAPSHOT 的就是正式 RELEASE(发布)版本。
SNAPSHOT 版本和 RELEASE 版本区别如下表。
区别 | SNAPSHOT 版本 | RELEASE 版本 |
定义 | 版本号中带有 -SNAPSHOT | 版本号中不带有 -SNAPSHOT |
发布仓库 | Snapshot 快照仓库 | Release 发行仓库 |
是否从远程仓库自动获取更新 | 在不更改版本号的前提下,直接编译打包时,Maven 会自动从远程仓库上下载最新的快照版本。 | 在不更改版本号的前提下,直接编译打包时,如果本地仓库已经存在该版本的模块,则 Maven 不会主动去远程仓库下载。 |
稳定性 | 快照版本往往对应了大量带有时间戳的构件,具有不稳定性。 | 发布版本只对应了唯一的构件,具有稳定性。 |
使用场景 | 快照版本只应该在组织内部的项目中依赖使用。 | Maven 项目使用的组织外的依赖项都应该时发布版本的,不应该使用任何的快照版本依赖,否则会造成潜在的风险。 |
发布前是否需要修改 | 当项目经过完善的测试后,需要上线时,应该将项目从快照版本更改为发布版本 | 不需要修改 |
示例
项目 MavenDemo02 依赖于 MavenDemo01,在 MavenDemo02 的开发过程中,使用 MavenDemo01 的 SNAPSHOT 版,可以强制拿到 MavenDemo01 的最新版。
打开 cmd 命令行窗口,进入 D:\Workshop\maven\MavenDemo02 目录,执行如下命令:
D:\Workshop\maven\MavenDemo02>mvn clean compile -U
命令执行结果如下:
[INFO] Scanning for projects... [WARNING] [WARNING] Some problems were encountered while building the effective model for com.example:MavenDemo02:jar:1.0-SNAPSHOT [WARNING] 'dependencies.dependency.systemPath' for com.example:MavenDemo01:jar should use a variable instead of a hard-coded path D:\Workshop\maven\MavenDemo01\target\MavenDemo01-1.0-SNAPSHOT.jar @ line 26, column 21 [WARNING] [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build. [WARNING] [WARNING] For this reason, future Maven versions might no longer support building such malformed projects. [WARNING] [INFO] [INFO] ----------------------< com.example:MavenDemo02 >----------------------- [INFO] Building MavenDemo02 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ MavenDemo02 --- [INFO] Deleting D:\Workshop\maven\MavenDemo02\target [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ MavenDemo02 --- [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\Workshop\maven\MavenDemo02\src\main\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ MavenDemo02 --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent! [INFO] Compiling 1 source file to D:\Workshop\maven\MavenDemo02\target\classes [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.943 s [INFO] Finished at: 2022-06-05T12:16:47+08:00 [INFO] ------------------------------------------------------------------------