比Maven快2~10倍的编译工具mvnd简介与实战

概述

maven-mvnd,可简称(或缩写)mvnd,the Maven Daemon。Apache Maven团队借鉴Gradle和Takari后开发的更快的构建工具。mvnd内嵌Maven,开发者可无缝从Maven迁移到mvnd。

参考资料:GitHub。

mvnd中会启动一个或多个守护进程,用来执行实际的构建服务。一个守护进程实例可以为来自mvnd客户端的多个连续请求提供Maven构建服务。当没有空闲的守护进程时来支撑构建请求时,mvnd可以并行生成多个守护程序。

mvnd使用GraalVM代替传统的JVM,GraalVM启动速度更快,占用的内存更少,在实行构建时不需要为每个构建启动新的JVM。GraalVM的JIT(Just In Time)实时编译特性也被运用到Maven构建作业中。JIT可大大减少编译时间,在重复构建过程中,JIT优化代码立即可用,也极大提高构建效率。

另外Maven插件在构建时不再需要多次加载,而是缓存在多个构建中。SNAPSHOT版本的Maven插件不会被缓存。

默认情况下,mvnd使用多个CPU内核并行构建模块。使用的内核数公式Math.max(Runtime.getRuntime().availableProcessors() - 1, 1)。如果代码不支持并行构建,在命令行添加-T1参数切换到串行构建。

相比Maven,mvnd的优势:

  • 运行构建的JVM不需要为每个构建重新启动;
  • Maven插件类的类加载器缓存在多个构建中,插件jars只会被读取和解析一次;
  • JVM中JIT生成的本机代码会被保留。与Maven相比,JIT编译花费的时间更少。在重复构建期间,JIT优化的代码立即可用。这不仅适用于来自Maven插件和Maven内核的代码,也适用于来自JDK本身的所有代码。

安装使用

下载地址,读者根据各自的操作系统选择。本文选择Windows系统1.0.1版本,这里选择下载zip压缩包(另外还有tar.gz压缩包)。解压缩后,将目录名maven-mvnd-1.0.1-windows-amd64重命名为mvnd-1.0.1。

目录如下:

进入到mvn目录下,发现和之前的Maven目录设置没有区别:

配置环境变量和之前使用Maven没有区别,过程略。与Maven的命令完全相同,改为mvnd即可:

mvnd与Maven互不干扰。

默认情况下,Maven下载的JAR包存放在C盘目录下,但C盘一般都是SSD,空间有限。于是会修改Maven的settings.xml配置文件,将JAR包放到D盘:

xml 复制代码
<localRepository>D:\maven\repository</localRepository>

在Maven项目工程里,即pom.xml文件所在目录里执行命令:mvnd clean -Dquickly,却发现mvnd在下载各种依赖JAR包,这些不应该早就下载好了吗?

发现C盘.m2目录下,确实多了个repository目录。与此同时,发现还有另一个目录:

看到这个daemon日志文件,也印证着上文所述:mvnd中会启动一个或多个守护进程。

想到在使用Maven时,需配置settings.xml文件。mvnd是不是也需要配置文件?

于是,找到mvnd安装目录conf下的mvnd.properties配置文件。分析此文件,不难发现最后一个配置项maven.settings,用于指定settings.xml文件路径:

复制代码
# The location of the maven settings file. The client normally uses default settings in {@code ~/.m2/settings.xml}.
# maven.settings=<path>

于是删除注释符,修改配置为:maven.settings=D:\maven\settings.xml,再次执行命令mvnd clean -Dquickly,结果报错:

分析报错,缺少转义字符?

尝试修改配置为:maven.settings=D:\\maven\\settings.xml,执行成功。

性能对比

Maven官宣,mvnd比Maven编译速度快。

此处暂时给不出严谨的对比数据,但是可以执行两条命令来验证一下是否如此(当然截图也不一定就肯定正确)。

另外,如上面某个截图所示,我使用的Maven版本为3.6.3,不算低(好吧,最新版是3.9.9,有点低了);mvnd版本为1.0.1,是最新版。

首先看clean -Dquickly命令。

某一次mvn clean -Dquickly执行结果截图:

耗时0.69s。不明白为何此处使用maven-clean-plugin2.5这么低的插件版本。

某一次mvnd clean -Dquickly执行结果截图:

耗时0.076s!是mvn clean命令耗时的10%。另外,多了个括号,Wall Clock。

再来看compile -Dquickly命令。

某一次mvn compile -Dquickly执行结果截图:

编译过程出现两个插件maven-resources-plugin和maven-compiler-plugin,耗时3.867s。

某一次mvnd compile -Dquickly执行结果截图:

编译耗时0.996,是mvn compile命令耗时的26%。另外上图编译过程中出现乱码。

声明:截图都是某一次执行结果。

事实上,反复多次执行,完全可以得出mvnd比mvn快不止2倍的结论。另外,mvnd.properties文件里还有很多配置项可以优化编译过程。

Wall Clock

参考Wall Clock and Monotonic Clock。

Wall Clock就是一般意义上的时间。

Monotonic Clock,单调时间,实际上它指的是从某个点开始后(如系统启动以后)流逝的时间,一定是单调递增的。

计算两个时间点的差值一定要用Monotonic Clock,因为Wall clock是可以被修改的,如计算机时间被回拨(比如校准或者人工回拨等情况),或闰秒(Leap Second),会导致两个Wall Clock可能出现负数。

因为操作系统或上层应用不一定完全支持闰秒,出现闰秒后系统时间会在后续某个点会调整为正确值,就有可能出现时钟回拨。当然也不一定,比如ntpdate就有可能出现时钟回拨,但ntpd就不会。

中文乱码

理论上,IDEA里Terminal控制台,mvn或mvnd命令基于如下maven-compiler-plugin配置:

xml 复制代码
<build>
	<pluginManagement>
		<plugins>
			<plugin>
			<!--by default groupId is org.apache.maven.plugins-->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.13.0</version>
				<configuration>
					<source>22</source>
					<target>22</target>
					<encoding>UTF-8</encoding>
					<showWarnings>true</showWarnings>
				</configuration>
			</plugin>
		</plugins>
	</pluginManagement>
</build>

而这个配置是没有问题的,为啥mvnd还是会出现中文乱码呢?

反复查看mvnd.properties配置文件,也没找到跟编码相关的配置项。

TODO:待解决。

现在时间:2024年8月24日01:59:18。老命要紧

日志解读

C盘目录下,类似于daemon-cbaabd83.log日志文件:

复制代码
Dispatch message: KeepAlive
Dispatch message: ProjectStopped{payload='yaml_groovy'}
Dispatch message: BuildFinished{exitCode=0}
No more message to dispatch
Daemon back to idle
Updating state to: Idle

然后在日志文件里发现如上图所示,也就是说mvnd命令没有问题,IDEA的Terminal控制台展示中文乱码?展示mvn命令正常?

daemon-cbaabd83.out.log日志文件:

复制代码
Starting daemon process: id = 8284f806, workingDir = E:\Java\maven\mvnd-1.0.1, daemonArgs: -classpath

都是些命令启动参数。

配置解读

参考

相关推荐
IT枫斗者枫哥5 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
代码方舟5 小时前
Java数据工程:利用天远全网运营商三要素优化线上实名认证合规体验
java·人工智能
BBmmo5 小时前
我的 Java 学习笔记 · 第 7 篇:泛型与通配符
java
独泪了无痕5 小时前
Hutool之RandomUtil:随机数生成的终极利器
java·后端
花开路口5 小时前
深入理解 Java/Kotlin 协变与逆变
java·kotlin
运行时异常5 小时前
【WMS 仓储系统集成 AI Agent 实战】第 7 讲:Vue3 前端工程化——Token 刷新锁、Markdown 渲染踩坑与权限体系
java
她的男孩5 小时前
开放接口限流从 20 改到 200 还是每分钟 20 次:拆完防重放+幂等+限流,我找到 5 个静默失效的坑
java·后端·架构
天天被压力6 小时前
【Python 量化取数指南 #13】Python 把行情落库:sqlite 一键存,回测随用随取
java·人工智能·python
天天被压力6 小时前
【Python 量化取数指南 #14】Python 清洗行情数据:复权停牌对齐,回测不翻车
java·人工智能·python
独泪了无痕6 小时前
开发利器Hutool之MapUtil的使用
java·后端