【Maven】(六)详细聊聊 Maven 的生命周期、阶段(phase)、插件目标(goal)
创始人
2024-06-02 09:46:29
0

文章目录

  • 1.前言
  • 2.生命周期
    • 2.1.生命周期的阶段
    • 2.2.插件目标
    • 2.3.其他插件绑定
      • 2.3.1.源码生成插件
      • 2.3.2.SpringBoot打包插件
  • 3.总结

1.前言

本系列文章记录了 Maven 从0开始到实战的过程,Maven 系列历史文章清单:

(一)5分钟做完 Maven 的安装与配置
(二)使用 Maven 创建并运行项目、聊聊 POM 中的坐标与版本号的规则
(三)Maven仓库概念及私服安装与使用 附:Nexus安装包下载地址
(四)图解Maven3依赖的功能特性:依赖范围、依赖传递、依赖冲突
(五)Maven模块的继承与聚合 多模块项目组织构建

在之前的内容中,我们使用了一个简单的 demo 来验证 Maven中的依赖传递、继承、聚合等特性,在构建demo的时候,已经在不知情的情况下,使用过了生命周期插件

在验证的过程中,多次使用到了一个指令 mvn clean install ,我们已经知道了 clean 是清理当前项目的 target 目录,install 是将当前项目打包并推送到本地仓库中去。这里的 cleaninstall 就是 Maven 的生命周期中的某个阶段,在每个阶段实际完成工作的就是插件

可能这段话比较抽象,没关系,接下来会详细的讲解,先看一本篇的主要内容:

  • Maven 生命周期详解:
    • 生命周期中的 阶段插件目标
    • 常见的生命周期指令
    • 插件与生命周期绑定使用

有一定的Maven经验和英文阅读能力的同学,建议看看官方文档。附:《Maven生命周期官方文档》

2.生命周期

我们在开发中描述的项目的生命周期,一般是指的是 编译、测试、打包、部署等过程,每个项目的构建生命周期或多或少都有一些差异,Maven 对构建的过程进行的抽象和统一,提出了 Maven生命周期这一个抽象的概念,它的作用是定义一条执行流程,而不会完成实际的工作,在每个流程节点中的工作都会交给具体实例对象去完成。

这个执行的流程中包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成等步骤,几乎覆盖了项目构建中的所有流程节点,我们可以按需选择其中的一部分步骤生成自己的项目包。

Maven 对流程、流程节点、具体工作都有专用的名词,如下:

  • 流程:生命周期(lifeCycle)
  • 流程节点:阶段 (phase)
  • 具体工作:插件目标 (plugin:goal)

Maven 的生命周期有三个,分别是cleandefaultsite,其中 site 使用的较少,另外两个都是经常会使用到的。这三个生命周期彼此是隔离开的个体,它们可以单独运行,也可以组合起来运行,例如:

# 单独清理
mvn clean# 单独构建
mvn package
mvn install
mvn deploy# 清理并构建
mvn clean install

仔细看上面的构建指令:mvn install,而不是 mvn default,这是因为在 mvn 指令后面接的是生命周期中的某个阶段,接下来就详细解释下阶段的含义。

2.1.生命周期的阶段

每个生命周期是由一个一个阶段组成的,我们先从一张官网的截图来感性的认知一下阶段:
在这里插入图片描述

上图就是 Maven 生命周期中的完整的阶段,第一次看到这个图的话,可能会看的有点眼花缭乱,但是没有关系,我们暂时先不管这些阶段在做什么,先对这些步骤做一下拆解。

在运行的时候会按照上图中从上到下的顺序运行,直到运行到指定的阶段为止,例如上面的 mvn clean install 指令,会按下面的步骤运行:

  1. 找到clean生命周期,从pre-clean开始往下执行,直到clean阶段执行完成。
  2. 找到default生命周期,从validate开始往下执行,直到install阶段执行完成。

这里的没有指定 site 直接忽略,cleandefault 大概会执行20多个阶段,看起来还是很多,但实际上这20多个阶段中有很大一部分是不会运行的,这涉及到一个特性:没有绑定插件目标的阶段,在生命周期中不会被调用(插件目标的概念可以看下面的标题2.2)。

If a build phase has no goals bound to it, that build phase will not execute.

这就好办了,我们只需要关注绑定了插件目标的阶段就好了,Maven 针对不同的打包格式,提供了不同的默认插件目标绑定规则,以打包成jar来举例:

在这里插入图片描述
上图就是我们日常工作中常用的阶段,相比上面那张图就简单多了,接下来一一解释一下这些阶段的含义:

  • clean:默认是清除target目录中的所有文件,避免将历史版本打到新的包中造成一些不在预期中的问题。
  • process-resources:将资源文件src/main/resources下的文件复制到target/classes目录中。
  • compile:将src/main/java下的代码编译成 class 文件,也放到target/classes目录中。
  • process-test-resources:将资源文件src/test/resources下的文件复制到target/test-classes目录中。
  • test-compile:将src/test/java下的代码编译成 class 文件,也放到target/test-classes目录中。
  • test:运行单元测试并在target/surefire-reports中生成测试报告。
  • package:将资源文件、class文件、pom文件打包成一个jar包。
  • install:将生成的jar包推送到本地仓库中。
  • deploy:将生成的jar包推送到远程仓库中。

现在我们执行一次deploy指令,看看控制台中打印出来的结果,对比一下是不是这些插件目标,篇幅问题,这里只放demo-a部分的结果,用红色字体标出的插件目标

[INFO] — maven-clean-plugin:3.1.0:clean (default-clean) @ demo-a —
[INFO] Deleting E:\workspace\code\dependency-demo\demo-a\target
[INFO]
[INFO] — maven-resources-plugin:3.2.0:resources (default-resources) @ demo-a —
[INFO] Using ‘UTF-8’ encoding to copy filtered resources.
[INFO] Using ‘UTF-8’ encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] — maven-compiler-plugin:3.8.1:compile (default-compile) @ demo-a —
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\workspace\code\dependency-demo\demo-a\target\classes
[INFO]
[INFO] — maven-resources-plugin:3.2.0:testResources (default-testResources) @ demo-a —
[INFO] Using ‘UTF-8’ encoding to copy filtered resources.
[INFO] Using ‘UTF-8’ encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO]
[INFO] — maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo-a —
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to E:\workspace\code\dependency-demo\demo-a\target\test-classes
[INFO]
[INFO] — maven-surefire-plugin:2.22.2:test (default-test) @ demo-a —
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.ls.maven.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.019 s - in com.ls.maven.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] — maven-jar-plugin:3.2.2:jar (default-jar) @ demo-a —
[INFO] Building jar: E:\workspace\code\dependency-demo\demo-a\target\demo-a-1.0.3.jar
[INFO]
[INFO] — maven-install-plugin:2.5.2:install (default-install) @ demo-a —
[INFO] Installing E:\workspace\code\dependency-demo\demo-a\target\demo-a-1.0.3.jar to E:\workspace\repository\com\ls\maven\demo-a\1.0.3\demo-a-1.0.3.jar
[INFO] Installing E:\workspace\code\dependency-demo\demo-a\pom.xml to E:\workspace\repository\com\ls\maven\demo-a\1.0.3\demo-a-1.0.3.pom
[INFO]
[INFO] — maven-deploy-plugin:2.8.2:deploy (default-deploy) @ demo-a —
Uploading to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/1.0.3/demo-a-1.0.3.jar
Uploaded to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/1.0.3/demo-a-1.0.3.jar (2.4 kB at 82 kB/s)
Uploading to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/1.0.3/demo-a-1.0.3.pom
Uploaded to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/1.0.3/demo-a-1.0.3.pom (876 B at 26 kB/s)
Downloading from nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/maven-metadata.xml
Downloaded from nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/maven-metadata.xml (298 B at 17 kB/s)
Uploading to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/maven-metadata.xml
Uploaded to nexus: http://192.168.200.101:8081/repository/maven-releases/com/ls/maven/demo-a/maven-metadata.xml (329 B at 15 kB/s)


注:运行deploy指令需要先配置私服,可以参考 (三)Maven仓库概念及私服安装与使用 附:Nexus安装包下载地址,将下面的配置改成成自己的私服地址。

nexushttp://192.168.200.101:8081/repository/maven-releases/nexushttp://192.168.200.101:8081/repository/maven-snapshots/

如果还想了解其他打包方式的插件目标绑定关系,可以到官网进行查阅。

2.2.插件目标

插件目标非常容易理解,其实就是在某个插件中的某个功能,例如:compiler:compile是属于 maven-compiler-plugin 里面的一个功能,compiler目标前缀(goalPrefix)compile就是目标(goal)

两者组成了一个坐标,绑定到了compile这个阶段上,当运行到这个阶段的时候,就会通过这个坐标找到对应编译功能的代码并运行。

跳过测试插件目标
我们每次执行构建时,到走到生命周期中的test阶段,就会把项目中的单元测试全都运行一遍,单元测试较多的时候运行会比较耗时,在项目没有强制要求不需自动运行单元测试的情况下,我们可以通过下面的指令跳过测试阶段。

mvn clean install -D maven.test.skip=true

……
[INFO] — maven-resources-plugin:3.2.0:testResources (default-testResources) @ demo-a —
[INFO] Not copying test resources
[INFO]
[INFO] — maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ demo-a —
[INFO] Not compiling test sources
[INFO]
[INFO] — maven-surefire-plugin:2.22.2:test (default-test) @ demo-a —
[INFO] Tests are skipped.
……

上面执行结果中,用红色标记的插件目标执行结果发生了变化,不再复制src/test下面的资源文件、也不再编译src/test目录下的代码,并且直接跳过了测试阶段。

2.3.其他插件绑定

除了Maven自带的默认插件以外,我们还可以引入官方或者三方编写的非默认的插件,与类似,在标签中通过坐标引入插件,通过执行计划

例如,我们有时候不仅需要将jar包推送到私服中,还需要将源码一并推送,方便使用者可以直接查看源码中的注释以及实现代码,这时候就需要引入源码插件。

2.3.1.源码生成插件

org.apache.maven.pluginsmaven-source-plugin3.0.1installbuild-sourcejar-no-fork

在这里插入图片描述
这里在install这个阶段加入了生成源码的插件目标,也就是说在install阶段上有了两个插件目标,从执行结果来看,两个插件目标都被依次执行了。这涉及到绑定插件目标的另一个特性:同一个阶段中可以绑定多个插件目标,在这个阶段中,会按照POM中定义的顺序执行

If a build phase has no goals bound to it, that build phase will not execute. But if it has one or more goals bound to it, it will execute all those goals.
multiple goals bound to a phase are executed in the same order as they are declared in the POM.

2.3.2.SpringBoot打包插件

SpringBoot的jar包与普通的包对比起来主要有两点差别:

  • 能够通过java -jar启动
  • jar包里面除了项目中本身的文件以外,还把3方jar包也一起打包了

Maven 自带的maven-jar-plugin插件不具备这种能力,于是需要引入SpringBoot的打包工具。

org.springframework.bootspring-boot-maven-plugin

运行 mvn clean package 查看运行结果,可以看到执行了repackage这个插件目标:
在这里插入图片描述


这里有个疑问,为什么这个插件不需要指定以及呢?

这是因为在pom.xml中继承了spring-boot-starter-parent,在这个pom中定义了,所以可以直接使用,就类似于

org.springframework.bootspring-boot-starter-parent2.6.7

再看一下父级pom中的定义:
在这里插入图片描述

这里没有指定phase,插件目标是怎么绑定到package阶段的呢?

这是因为在编写插件的时候,在插件的配置文件中就已经指定了repackage这个插件目标绑定在package这个阶段上了,在spring-boot-maven-plugin-2.6.7.jar 这个包中,我们可以找到一个plugin.xml的配置文件,打开后可以查看到如下的内容:
在这里插入图片描述

如果你对自己编写一个 Maven 插件没有什么需求的话,了解到这里就已经足够了,这个配置文件在后续的自定义 Maven 插件中还会更详细的讲解。

3.总结

本篇主要讲解的是Maven 通过生命周期阶段插件目标的绑定来实现项目的构建流程,主要涉及到以下的知识点:

  • 生命周期有三种,分别是clean,default,site
  • 每种生命周期都由多个阶段组成
  • 执行构建时,会按照阶段顺序从上到下的执行,但只有绑定了插件目标阶段才会执行
  • 可以在通过标签引入插件,通过来定义执行计划,通过绑定阶段插件模板
  • 除了在pom.xml中指定阶段与插件目标的绑定关系之外,还可以通过插件的配置文件plugin.xml进行指定

下面是一张以打包成jar为例的执行阶段图,我们大部分的项目都会按照下图的顺序进行处理。
在这里插入图片描述

相关内容

热门资讯

122.(leaflet篇)l... 听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
Vue使用pdf-lib为文件... 之前也写过两篇预览pdf的,但是没有加水印,这是链接:Vu...
PyQt5数据库开发1 4.1... 文章目录 前言 步骤/方法 1 使用windows身份登录 2 启用混合登录模式 3 允许远程连接服...
Android studio ... 解决 Android studio 出现“The emulator process for AVD ...
Linux基础命令大全(上) ♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维...
再谈解决“因为文件包含病毒或潜... 前面出了一篇博文专门来解决“因为文件包含病毒或潜在的垃圾软件”的问题,其中第二种方法有...
南京邮电大学通达学院2023c... 题目展示 一.问题描述 实验题目1 定义一个学生类,其中包括如下内容: (1)私有数据成员 ①年龄 ...
PageObject 六大原则 PageObject六大原则: 1.封装服务的方法 2.不要暴露页面的细节 3.通过r...
【Linux网络编程】01:S... Socket多进程 OVERVIEWSocket多进程1.Server2.Client3.bug&...
数据结构刷题(二十五):122... 1.122. 买卖股票的最佳时机 II思路:贪心。把利润分解为每天为单位的维度,然后收...
浏览器事件循环 事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间࿰...
8个免费图片/照片压缩工具帮您... 继续查看一些最好的图像压缩工具,以提升用户体验和存储空间以及网站使用支持。 无数图像压...
计算机二级Python备考(2... 目录  一、选择题 1.在Python语言中: 2.知识点 二、基本操作题 1. j...
端电压 相电压 线电压 记得刚接触矢量控制的时候,拿到板子,就赶紧去测各种波形,结...
如何使用Python检测和识别... 车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这项技术结合了计...
带环链表详解 目录 一、什么是环形链表 二、判断是否为环形链表 2.1 具体题目 2.2 具体思路 2.3 思路的...
【C语言进阶:刨根究底字符串函... 本节重点内容: 深入理解strcpy函数的使用学会strcpy函数的模拟实现⚡strc...
Django web开发(一)... 文章目录前端开发1.快速开发网站2.标签2.1 编码2.2 title2.3 标题2.4 div和s...