文章目录

    • 概览
    • 并行执行
      • Wall-Clock
    • 当前发布只重新编译修改模块
    • 并行执行单元测试
    • maven-mvnd 特性:
    • maven依赖优化
    • 小结

概览

【1】maven支持并发设置多线程编译
【2】子模块是可以并行编译打包的
【3】每个模块开启一个线程,但是这个线程不是立刻开启的,是由打包程序自己决定启用多少个线程
【4】dependency:analyze优化,寻找那些不需要的依赖,然后移除
【5】并发执行TEST
【6】适当的跳过某些模块,当前构建只处理改动的模块

并行执行

默认情况下Maven 会按顺序串行构建所有的模块,这往往不能充分利用CPU的性能,我们可以设置maven构建为并行模式,即多线程构建对应的模块。

mvn -T 4 install -- will use 4 threads-- 使用4个线程去构建mvn -T 1C install -- 每一个CPU核使用一个线程,逻辑CPU核数

通常情况下建议使用-T 1C 每个CPU一个线程,Linux下可以通过lscpu查询,Windows可以通过任务管理器查看。

Wall-Clock

在某些情况下我们在构建后会出现如下红框所示的提示

默认情况下(没有 -T),Maven 会按顺序而不是并行构建所有模块。 因此,只有一个流程,实际处理时间是累计的。
您以 4 个线程开始构建,因此 总时间除以 4 个线程,总 CPU 时间保持不变(即每个CPU实际处理的时间,但不是最终结果的时间),但您所用的时间是总的时间除以4个线程的一些并行化开销。 这是你看墙上的时钟时看到的时间,因此它被称为挂钟时间。

当前发布只重新编译修改模块

对于一些大型多模块的项目来说,很多时候的发布或者说紧急上线发布都只是修改一小段代码,绝大多数情况仅仅这涉及一个模块。但是在以往的情况下我们却需要clean 和package所有的模块,这显然有些浪费,所以如果需要追求效率,那么可以设置本次发布只编译其中特定的一个或多个模块;

mvn clean install -DskipTests-pl ruoyi-api -T 1C

并行执行单元测试

在执行构建的过程中,单元测试往往会占据较大的一部分执行时间。默认情况下单元测试的执行也是串行执行的,针对这个也是可以进行并行化优化的,maven-sure-fire 插件提供了并行测试的方式,我们可以使用它来优化速度,下面的一个配置作为一个基本的参考

<plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version><configuration><argLine>-Xmx2G -XX:MaxPermSize=1G -XX:-UseSplitVerifier -XX:-TieredCompilation -XX:TieredStopAtLevel=1</argLine><parallel>methods</parallel><forkCount>3C</forkCount><reuseForks>true</reuseForks><threadCount>20</threadCount></configuration></plugin>

配置要求:
Junit 4.7+
Surefire plugin 2.16+
Maven Daemon
mvnd 是 Maven Daemon 的缩写 ,翻译成中文就是 Maven 守护进程。
mvnd 是 apache/maven 的一个子项目,它并不是一个全新的构建工具,而是对 maven 的扩展。它内置了 maven,其实现原理是构建了一个或者多个 maven 守护进程来执行构建服务。

maven-mvnd 特性:

【1】嵌入 Maven (所以不需要单独安装 Maven);maven 过渡到 maven-mvnd的过程中实现无缝切换!所以不需要再安装maven或进行复杂的配置更改。
【2】实际的构建发生在一个长期存在的后台进程中,也就是守护进程。如果没有为构建请求服务的空闲守护进程,则可以并行产生多个守护进程。
【3】一个守护进程实例可以处理来自 mvnd 客户机的多个连续请求。
【4】使用 GraalVM 构建的本地可执行文件。与传统的 JVM 相比,它启动更快,使用的内存更少。
【5】maven所支持的命令它也是支持的,需要将mvn改成mvnd即可。

下载链接:https://github.com/mvndaemon/mvnd/releases

其中:bin目录是mvnd的执行程序,conf配置文件目录,mvn就是内嵌的maven模块,其中和我们之前用的maven一样,是可以直接将原来的maven的setting配置文件复制过来的。

# maven 打包命令 mvn clean package -Dmaven.test.skip=true

# mvnd 打包命令mvnd clean package -Dmaven.test.skip=true


注意:上面的结果并不是在所有情况下都有很大的提升,尤其是在第一次构建时需要拉取插件等肯定要耗时的,但是在我的电脑上(4核)多次测试下,基本上是有一倍左右的性能提升的。

maven依赖优化

在很多的项目中,往往都存在一些冗余的JAR包依赖,可能是某次的测试加入但是之后没有删除,可能是引用传递的依赖,也可能是历史代码但在后面升级后已经有其他的替换方案了,可没有剔除原先的依赖等等情况。想要更好的提升构建速度,那么就需要从源头出发,优化项目本身的大小,剔除一些无用的依赖。我们可以通过mvn dependency:analyze的方式去分析依赖情况。

mvn dependency:analyze


如上图所示,可以看到俩行主要的提示
【Used undeclared dependencies found】
这个是指某些依赖的包在代码中有用到它的代码,但是它并不是直接的依赖(就是说没有在pom中直接声明),是通过引入传递下来的包。
即项目在pom中声明了A.jar的依赖(没有声明B.jar的依赖) ,但是A自己的依赖中引入了B.jar,说明project中的代码用到了B.jar的代码 这个时候你就可以把B.jar直接声明在pom中。

【Unused declared dependencies found】
这个是指我们在pom中声明了依赖,但是在实际代码中并没有用到这个包,也就是多余的包。这个时候我们就可以把这个依赖从pom中剔除。

注意事项:
【1】上面的工具只是帮助我们分析了依赖,但是注意并不是说完全就可以确定对应的依赖可以直接剔除。在决定剔除之前和之后要有仔细的核对和检查,保证不会有影响。
【2】在上面分析之后,可以通过mvn dependency:tree或者IDEA的maven依赖插件去分析下对应的依赖情况,做下核对检查。

小结

【1】本文的主要的优化还是利用多线程的方式打包多模块,其中多模块的数量越多且项目越大那么所取得的优化效果也会越加的明显。
【2】本文多次提及CPU的核数,因此如果构建服务器CPU核数就一个那么就没有必要了,当然就目前来看,maven构建的服务器应该很少是单核的。
【3】需要注意,多线程不一定就比单线程快,这意味这个优化并非一定可以取得好的效果,多线程的启动和切换需要成本,具体的优化需要根据自己的项目多次实践比对。
【4】文章中所提到的只编译修改模块,虽然在发布编译时需要修改命令,但是其取得的效果是很好的,这个可以通过Jenkins设置变量配合一些条件判断进行处理。尤其是跳过一些编译时间长且没有发生变动的代码模块尤其有效,避免了一些无用的操作等待。
【5】合理使用mvn dependency:analyze工具,移除无用的JAR依赖,给项目瘦身,减少项目的体积,从来源上优化。