Springboot的jar包瘦身
困扰来源
平时我们开发的项目都用jenkins打包,从jenkins到应用服务器都是内网传输,300M的jar也就个把秒钟。
发版工作也就打包时花点时间,jar包传输没烦恼。
但是最近做的项目都需要远程部署,只能通过微信,邮箱,网盘等工具上传,再下载。
最垃圾的就是在用户端给服务器上传,开发机上上传文件的速度通常是20Kb/s左右。
麒麟开发机器打包也很慢,种种造成了一次部署的费劲。

分析
我们的打包命令是
mvn clean package
这本身是不会把pom.xml里的依赖都打进去的。但是Spring Boot项目的pom.xml文件中一般都会带有spring-boot-maven-plugin插件,插件的作用就是会将依赖的jar包全部打包进去,该文件包含了所有的依赖和资源文件,的确是方便。
但是也导致打出来的包比较大。
$ ll -h api-platform/target/api-platform-1.0-SNAPSHOT.jar
-rw-r--r-- 1 mahaiqiang staff 345M Aug 22 10:35 api-platform/target/api-platform-1.0-SNAPSHOT.jar
我们的系统上线还没有到1.0版本呢,必然有需求迭代和Bug修复,那也就免不了进行重新打包部署。
现在客户环境有一个紧急致命Bug,你也很快定位到了问题,就改一行代码的事情,当提交代码并完成构建打包给运维之后。
你问他怎么样,他说:"因为打包的jar很大,一直处于上传中......."
客户也说领导等着看呢~~
瘦身原理
先通过解压看看我们jar包里的依赖
tar -zxvf api-platform/target/api-platform-1.0-SNAPSHOT.jar
查看里面的文件主要是BOOT-INF,META-INF,org三部分:
$ ll
total 705640
drwxr-xr-x 6 mahaiqiang staff 192B Aug 22 10:35 BOOT-INF
drwxr-xr-x 4 mahaiqiang staff 128B Aug 22 10:35 META-INF
-rw-r--r--@ 1 mahaiqiang staff 345M Aug 22 10:35 api-platform-1.0-SNAPSHOT.jar
drwxr-xr-x 3 mahaiqiang staff 96B Feb 1 1980 org
打开 BOOT-INF
$ ll BOOT-INF/
total 56
drwxr-xr-x 10 mahaiqiang staff 320B Aug 22 10:35 classes
-rw-r--r-- 1 mahaiqiang staff 12K Aug 22 10:35 classpath.idx
-rw-r--r-- 1 mahaiqiang staff 12K Aug 22 10:35 layers.idx
drwxr-xr-x 274 mahaiqiang staff 8.6K Aug 22 10:35 lib
classes: 当前项目编译好的代码是放在 classes 里面的,classes 部分是非常小的。
lib: 我们所依赖的 jar 包都是放在 lib 文件夹下,lib部分会很大。
lib的大小:
du -h
344M ./lib
项目虽然依赖会很多,但是当版本迭代稳定之后,依赖基本就不会再变动了,尤其是对外部的依赖。
思路很简单,把lib里面的包都放到服务器上,在启动时指定lib路径就行了。
当然,自己开发的一些marven模块也不能都放到服务器上,最好是打到jar里。
第一点,查jar包启动路径就知道可以指定参数
java -Dloader.path=./lib -jar xxx.jar
也就是把lib跟jar放一起就完事了。
第二点,使用spring-boot-maven-plugin的executable搞定。
瘦身修改
依赖拆分配置 只需要在项目pom.xml文件中添加下面的配置:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <executable>true</executable> <layout>ZIP</layout> <!--这里是填写需要包含进去的jar, 必须项目中的某些模块,会经常变动,那么就应该将其坐标写进来 如果没有则nothing ,表示不打包依赖 --> <includes> <include> <groupId>cn.cetc22</groupId> <artifactId>api-commons</artifactId> </include> <include> <groupId>cn.cetc22</groupId> <artifactId>Algms</artifactId> </include> </includes> </configuration> </plugin> </plugins> </build>对于第一次打包,可以用下面的配置获得到copy到服务器的
lib目录.<!--拷贝依赖到jar外面的lib目录--> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!--指定的依赖路径--> <outputDirectory> ${project.build.directory}/lib </outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build>打包后大小
$ ll -lh
total 10184
-rwxr--r-- 1 mahaiqiang staff 4.3M Aug 22 11:08 api-platform-1.0-SNAPSHOT.jar
-rw-r--r-- 1 mahaiqiang staff 709K Aug 22 11:08 api-platform-1.0-SNAPSHOT.jar.original
drwxr-xr-x 10 mahaiqiang staff 320B Aug 22 11:08 classes
drwxr-xr-x 3 mahaiqiang staff 96B Aug 22 11:07 generated-sources
drwxr-xr-x 3 mahaiqiang staff 96B Aug 22 11:08 generated-test-sources
drwxr-xr-x 283 mahaiqiang staff 8.8K Aug 22 11:08 lib
drwxr-xr-x 3 mahaiqiang staff 96B Aug 22 11:08 maven-archiver
drwxr-xr-x 3 mahaiqiang staff 96B Aug 22 11:07 maven-status
drwxr-xr-x 3 mahaiqiang staff 96B Aug 22 11:08 test-classes
- 指定lib启动程序

完美!!!
- 检查
api-platform-1.0-SNAPSHOT.jar是否是想要的东西
- 第一项: jar包里包含我们自己的maven模块的包
$ pwd
/Users/mahaiqiang/git/redcreation/jcdsj-backend/api-platform/target/BOOT-INF/lib
# mahaiqiang @ mahaiqiangdeMacBook-Air in ~/git/redcreation/jcdsj-backend/api-platform/target/BOOT-INF/lib on git:dev2 x [11:33:25]
$ ll
total 7040
-rw-r--r-- 1 mahaiqiang staff 2.3M Aug 7 14:30 Algms-0.8.08-Algms.jar
-rw-r--r-- 1 mahaiqiang staff 1.1M Aug 22 11:06 api-commons-1.0-SNAPSHOT.jar
-rw-r--r-- 1 mahaiqiang staff 29K Feb 1 1980 spring-boot-jarmode-layertools-2.6.2.jar
- 确认删除了
lib目录下的这两个依赖 删除后启动项目,启动成功。
结束
有了这个调整,我们的多个jar工程,只需要指定各自的lib目录就可以了。