易君召
易君召
发布于 2026-10-23 / 2 阅读
0

不同工具打包 JAR 效率对比

说明:这里的「效率」分为 打包速度(构建耗时)、增量构建效率、内存占用、产物大小、依赖处理能力、原生瘦身能力;测试基准:SpringBoot 3.x Java17 项目,常规 Web 工程 + 20~40 个三方依赖,区分 普通 JAR(非可执行) 和 胖 JAR(可执行 fat-jar)。

一、工具清单 & 核心原理

工具

底层

打包产物

核心原理

maven-jar-plugin

Maven

普通 JAR(仅自己代码,不含依赖)

直接编译 class + 资源,不打进依赖;速度最快

maven-assembly-plugin

Maven

FatJar

遍历依赖解压、重定向资源,无特殊缓存;容易资源冲突

spring-boot-maven-plugin

Maven

SpringBoot 可执行胖 JAR

自定义布局(BOOT-INF),不解压依赖,以 jar:jar 嵌套存储,这是它速度优于 assembly 的关键

Gradle Jar Task

Gradle

普通 JAR

Gradle 增量 Task、输入输出快照缓存

Gradle bootJar

SpringBoot Gradle 插件

SpringBoot 胖 JAR

和 boot-maven 布局一致,基于 Gradle 增量构建模型

ShadowJar(com.github.johnrengelman.shadow)

Gradle/Maven

FatJar

解压所有依赖、重定位包名(relocate),处理 SPI;开销大

jdk jar 命令(原生)

JDK

普通 JAR

直接 zip 打包,无依赖处理,纯 IO

关键知识点:

  • 不解压嵌套模式(SpringBoot bootJar/boot:repackage):依赖以 .jar 原样嵌套在 BOOT-INF/lib,不需要解压所有依赖,CPU 开销低;

  • 解压合并模式(assembly /shadow):所有依赖全部解压,class 平铺,需要扫描、去重、SPI 合并、包重定位,CPU+IO 开销显著更高。

二、效率维度对比表

⚠️ 速度评分:⭐越快越好;产物大小:越小越好;增量:增量构建是否能跳过不变部分

工具

首次全量打包速度

增量构建速度

内存占用

产物大小

依赖冲突处理

适用场景

JDK jar 原生命令

⭐⭐⭐⭐⭐

❌无增量

极低

最小(仅 class)

不处理依赖

只打包自身 class,无依赖

maven-jar-plugin

⭐⭐⭐⭐⭐

Maven 增量有限

低

最小

不处理依赖

类库 SDK,普通 thin jar

Gradle Jar

⭐⭐⭐⭐⭐

⭐⭐⭐⭐⭐(增量很强)

低

最小

不处理依赖

内部 SDK、公共组件

spring-boot-maven-plugin(boot:repackage)

⭐⭐⭐⭐

⭐⭐(Maven 增量弱,Maven 本身没有原生增量 task)

中

中等(嵌套 jar,几乎无膨胀)

一般,资源冲突容易踩坑

SpringBoot 官方推荐

Gradle bootJar

⭐⭐⭐⭐

⭐⭐⭐⭐⭐(增量优秀)

中

和 boot-maven 一致

同上

Gradle + SpringBoot 首选

maven-assembly-plugin

⭐⭐

⭐(几乎无增量)

高

偏大(解压平铺,重复资源)

弱,容易文件覆盖

简单胖包,不推荐 SpringBoot

ShadowJar

⭐

⭐(增量一般,relocate 开销大)

很高

偏大(relocate 后 class 重写)

很强,支持包重定位、SPI 合并

独立 CLI 工具、避免依赖包冲突

三、耗时定性结论(实测经验值,Java17,40 个依赖 SpringBoot Web)

  1. 普通 thin jar(不含依赖)梯队jdk jar ≈ maven jar ≈ gradle jar

    • 全量:几十 ms ~ 200ms 级别

    • Gradle Jar 增量:代码没改动直接跳过,几乎 0 耗时;Maven Jar 增量能力弱很多,Maven 靠maven-compiler-plugin增量编译,打包阶段还是会执行。

  2. SpringBoot 官方胖 Jar 梯队(嵌套模式)Gradle bootJar > spring-boot-maven-plugin

    • 全量:1~4s(取决于依赖数量、磁盘 IO)

    • Gradle 优势:增量构建是最大亮点,只有 class / 资源变更才重新打包;Maven 本身没有 Task 输入输出快照,每次package都会执行 repackage,缓存差。

  3. 解压合并型 FatJar(assembly /shadow)

    • assembly:全量 5~15s,依赖越多越慢;大量小文件解压、写入,磁盘 IO 瓶颈明显

    • ShadowJar:最慢,relocate 包重定位会逐 class 字节码改写;依赖多 + 大量 relocate 规则下几十秒都有可能

✅ 核心瓶颈拆解:

  1. IO 瓶颈:解压大量 jar 包、成千上万 class 文件读写(assembly/shadow)

  2. CPU 瓶颈:ShadowJar 字节码重定位、SPI 文件合并

  3. 构建模型瓶颈:Maven 是线性顺序执行、增量能力弱;Gradle 是基于输入输出(inputs/outputs)的增量 + 并行模型

四、产物大小对比重点

  • bootJar /boot:repackage:依赖是原 jar 原样嵌套,几乎不增加额外体积,只是打包封装;

  • assembly:解压平铺,如果多个依赖有同名资源(log 配置、META-INF),会覆盖或保留一份,体积略小 / 略大不稳定;

  • ShadowJar:relocate 会修改 class 常量池,class 文件体积会轻微变大;

  • thin jar:只有自己业务代码,体积最小。

五、内存占用

  • 原生 jar/maven jar:几十 MB;

  • bootJar:几百 MB;

  • ShadowJar:很容易冲到 1G+,依赖多 + relocate 时,ASM 字节码处理吃堆内存,经常需要调 -Xmx。

六、调优手段(提升打包效率)

1)Maven boot 打包提速

<!-- 开启boot插件分层打包,同时支持构建缓存 -->
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>enabled</layers>
        <!-- 排除不需要的开发依赖,减少lib数量 -->
        <excludes>...</excludes>
    </configuration>
</plugin>

Maven 本身增量弱,方案:使用 maven-build-cache-extension 做远程 / 本地构建缓存。

2)Gradle bootJar 提速(收益最大)

  • 开启守护进程 org.gradle.daemon=true

  • 开启构建缓存 org.gradle.caching=true

  • 并行 org.gradle.parallel=true

  • 对 bootJar 开启增量(默认已经支持,不要自己改写 outputs 破坏增量)

  • 用 --offline、排除不必要依赖、runtimeOnly 精细化管理依赖

3)ShadowJar 提速

  • 减少 relocate 规则,只对冲突包重定位,不要全局 relocate

  • 开启 mergeServiceFiles()、exclude 剔除无用资源

  • 给 Gradle 分配更大堆:org.gradle.jvmargs=-Xmx2g

4)通用:优先分层镜像,而不是一味打包胖 JAR

SpringBoot Layered JAR:打包耗时几乎不变,但是 Docker 镜像分层推送拉取更快;很多人混淆「打包 JAR 速度」和「镜像分发效率」。

七、选型建议

  1. 内部 SDK、公共组件、不需要独立运行:Gradle Jar / maven-jar-plugin(最快)

  2. SpringBoot Web 服务,线上部署:优先 Gradle bootJar;Maven 项目就用 spring-boot-maven-plugin

  3. 需要包名隔离、独立 CLI 工具、依赖版本冲突:ShadowJar(接受打包慢的代价)

  4. 老项目简单胖包,无复杂冲突:assembly(不推荐新项目)

  5. 极致简单脚本打包:jdk jar 命令

八、常见误区澄清

  1. ❌ 误区:ShadowJar 比 SpringBoot bootJar 更好 ✅ 正解:底层模型完全不同;bootJar 是嵌套 jar launcher,打包速度快、无字节码修改;ShadowJar 是解压合并 + 字节码改写,代价很高,只解决包冲突场景。

  2. ❌ 误区:Maven 打包一定比 Gradle 慢 ✅ 正解:全量打包差距不大;增量场景差距巨大,Gradle 增量模型是天然优势。

  3. ❌ 误区:胖 JAR 越小包越快 ✅ 正解:打包速度主要看「是否解压依赖、是否字节码改写」,不是单纯体积。


本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。

原文链接 https://www.yijunzhao.cn/archives/jar-packaging-tools-efficiency-comparison

欢迎访问 小易撩挨踢

https://www.yijunzhao.cn/