概述
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盘:
<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-plugin
2.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
配置:
<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
都是些命令启动参数。