最近开发的项目中,采用了微服务,存在大量的模块,每次全量打包编译时都很慢,就开始着手考虑优化的方向。
由于是采用的maven构建项目,因此本文着重介绍优化maven打包的速度。
采用多线程
命令行可以使用 mvn clean package -T -1C
若使用idea,可以在idea中配置。如下图
采用maven-build-cache-extension插件
若你的项目中存在多个模块,或者编译打包过程中存在多个生命周期goal较为复杂,可以考虑使用上述插件。
maven-build-cache-extension会在你第一次打包时,分析源代码,项目模型,插件及其参数生成唯一的key,并将package文件缓存在本地磁盘中。后续的打包中若该模块文件没有变动,则会跳过该maven生命周期,复用缓存中的文件。
如何使用maven-build-cache-extension插件
- 可以在项目的根目录创建 .mvn文件夹,将extensions.xml放在该文件夹内。
文件内容如下:
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extension>
<groupId>org.apache.maven.extensions</groupId>
<artifactId>maven-build-cache-extension</artifactId>
<version>1.0.1</version>
</extension>
</extensions>
或者 在全局pom.xml 依赖的build标签下 添加该插件的依赖
<build>
<extensions>
<extension>
<groupId>org.apache.maven.extensions</groupId>
<artifactId>maven-build-cache-extension</artifactId>
<version>1.0.1</version>
</extension>
</extensions>
</build>
- 通过 .mvn下的 maven-build-cache-config.xml 来自定义配置缓存插件
文件示例如下(已对常用标签添加注释):
<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/BUILD-CACHE-CONFIG/1.0.0 https://maven.apache.org/xsd/build-cache-config-1.0.0.xsd">
<!--
Template Maven build cache configuration
-->
<configuration>
<!--是否开启缓存功能-->
<enabled>true</enabled>
<!--校验算法 XX或者XXMM性能更好-->
<hashAlgorithm>SHA-256</hashAlgorithm>
<validateXml>true</validateXml>
<!--是否开启远程缓存功能-->
<remote enabled="true">
<url>http://host:port</url>
</remote>
<local>
<!--缓存的位置,不添加该标签,默认和本地maven仓库在同一层,文件夹名称为build-cache-->
<location>/var/jenkins_home/build-cache/</location>
<!--同一模块最大缓存数量-->
<maxBuildsCached>3</maxBuildsCached>
</local>
<projectVersioning adjustMetaInf="true"/>
</configuration>
<input>
<global>
<!--那些类型的文件参与校验-->
<glob> {*.java,*.groovy,*.yaml,*.svcd,*.proto,*assembly.xml,assembly*.xml,*logback.xml,*.vm,*.ini,*.jks,*.properties,*.sh,*.bat} </glob>
<includes>
<!--指定参与缓存校验的文件夹-->
<include>src/</include>
</includes>
<!--剔除不参与缓存校验的文件夹 需要注意将于打包编译无关的文件剔除,提高缓存命中率-->
<excludes>
<exclude>pom.xml</exclude>
</excludes>
</global>
<!--该插件也会获取其他maven-plugin中的文件地址将其列如缓存校验,如果想排除其他maven插件中的地址 可以在这边设置-->
<plugins>
<plugin artifactId="codegen">
<effectivePom>
<excludeProperties>
<excludeProperty>111</excludeProperty>
</excludeProperties>
</effectivePom>
<dirScan mode="auto">
<excludes>
<exclude tagName="outputDirectory"/>
<exclude tagName="directory"/>
</excludes>
<tagScanConfigs>
<tagScanConfig tagName="someProperty" glob="*.java" recursive="false"/>
</tagScanConfigs>
</dirScan>
<executions>
<execution>
<execIds>
<execId>1</execId>
<execId>2</execId>
</execIds>
<dirScan mode="auto">
<includes>
<include tagName="protolocation" recursive="false" glob="*.proto"/>
</includes>
</dirScan>
</execution>
</executions>
</plugin>
</plugins>
</input>
<!--如果命中缓存,则会跳过该maven生命周期,若某些插件绑定了该生命周期也会跳过,如果你想要无论如何都执行该插件,可以在此处配置-->
<executionControl>
<runAlways>
<plugins>
<plugin artifactId="maven-failsafe-plugin"/>
</plugins>
<executions>
<execution artifactId="maven-deploy-plugin">
<execIds>
<execId>my-execution-id</execId>
</execIds>
</execution>
</executions>
<goalsLists>
<goalsList artifactId="maven-install-plugin">
<goals>
<goal>install</goal>
</goals>
</goalsList>
<goalsList artifactId="maven-deploy-plugin">
<goals>
<goal>deploy</goal>
</goals>
</goalsList>
<goalsList artifactId="bb-sdk-codegen">
<goals>
<goal>deploy-local</goal>
</goals>
</goalsList>
</goalsLists>
</runAlways>
</executionControl>
</cache>
若在maven打包时出现:
16:40:37 [INFO] Scanning for projects...
16:40:37 [INFO] Loading cache configuration from /var/jenkins_home/workspace/oa-test/.mvn/maven-build-cache-config.xml
16:40:37 [INFO] Using SHA-256 hash algorithm for cache
16:40:38 [INFO] ------------------------------------------------------------------------
说明已经启用该插件。
若出现:
6:40:40 [INFO] Project inputs calculated in 13 ms. SHA-256 checksum [7eb42d63ea3aa3167e440d462f52d744e385b2ebe86ace149842b9efc0a73121] calculated in 6 ms.
16:40:40 [INFO] Attempting to restore project com.pttx:swagger from build cache
16:40:40 [INFO] Local build found by checksum 7eb42d63ea3aa3167e440d462f52d744e385b2ebe86ace149842b9efc0a73121
16:40:40 [INFO] Found cached build, restoring com.pttx:swagger from cache by checksum 7eb42d63ea3aa3167e440d462f52d744e385b2ebe86ace149842b9efc0a73121
16:40:40 [INFO] Skipping plugin execution (cached): resources:resources
16:40:40 [INFO] Skipping plugin execution (cached): compiler:compile
16:40:40 [INFO] Skipping plugin execution (cached): resources:testResources
16:40:40 [INFO] Skipping plugin execution (cached): compiler:testCompile
16:40:40 [INFO] Skipping plugin execution (cached): surefire:test
16:40:40 [INFO] Skipping plugin execution (cached): jar:jar
则说明命中缓存。
经实践,该项目打包+构建镜像+推送 共耗时 9分钟左右,
优化后若代码每次改动不大,耗时2分钟左右,优化效果还是比较明显的。
Tips
需要注意的是,如果你采用命令行打包maven项目,例如 mvn clean package docker:build
该命令行 会导致该缓存插件不工作。
究其原因是该插件只对maven的生命周期生效, mvn clean package docker:build 中 的 docker:build 该插件没有绑定生命周期 而是直接在命令行中触发该插件的goal
因此解决方法是在该maven插件中添加对生命周期的绑定。
例如:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker.plugin.version}</version>
<executions>
<execution>
<id>my-build</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
然后在命令行中打包命令就变为:
mvn clean package
这样该插件就会正常工作。