August 22, 2023
By: 马海强

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-pluginexecutable搞定。

瘦身修改

  1. 依赖拆分配置 只需要在项目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>
    
    
  2. 打包后大小

$ 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

  1. 指定lib启动程序

完美!!!

  1. 检查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目录就可以了。

Tags: jar