Spring Boot 打包瘦身:依赖分离的两种方式(IDEA Artifacts vs Maven 插件)
平时用 spring-boot-maven-plugin 打出来的是一个胖 jar(fat jar),所有依赖都塞在 BOOT-INF/lib 里,单文件几十上百 MB。但有些场景我们更希望主 jar 只放自己的代码,依赖单独抽出来放到一个 lib 目录:
- 每次只改业务代码时,发布包很小,依赖不用反复传输;
- 多个服务共用同一批依赖时,便于复用;
- 方便排查具体依赖的版本与内容。
本文整理两种实现”依赖分离”的方式:IDEA 自带的 Artifacts(手动 GUI)和 Maven 插件(构建工具原生)。先说结论:能用 Maven 就用 Maven,IDEA Artifacts 方式可行但脆弱、不可复现。
一、IDEA Artifacts 方式(手动)
这是网上流传较广的做法,纯靠 IDEA GUI,不依赖构建工具。
操作步骤
确保有一个带
main方法的启动类(即@SpringBootApplication主类)。菜单
File > Project Structure > Artifacts。点
+→JAR→ From Module with dependencies。弹窗里设置导出信息:
- Main Class 选你自己的启动类;
- MANIFEST.MF 的目录不要用默认值,建议设置成项目根目录(默认值经常导致路径不对)。
关于 “JAR files from libraries” 的两个选项:
选项 效果 extract to the target JAR 打成一个胖 jar(依赖解压进主 jar) copy to the output directory and link via manifest 主 jar + 外部依赖 jar,通过 MANIFEST.MF的Class-Path链接 ← 依赖分离选这个勾上 include in project build,设置好
Output directory,OK。菜单
Build > Build Artifacts > 选中目标 > Build,到Output directory即可看到 jar 和依赖。
这种方式的坑
- 不可复现:纯手点,配置不进版本控制,换机器/换人要重配。
- Class-Path 是相对路径:运行时
lib目录必须和主 jar 保持相同相对位置,挪动就启动失败。 - 不理解 Spring Boot 布局:IDEA 生成的是通用 JAR,没有
BOOT-INF,Main-Class必须手动指向你自己的启动类,而不是 Spring 的JarLauncher。 - 资源/配置易漏:
application.yml等是否打进去、是否外置,都要手动确认。
一个反而是优点的地方:依赖分离后,每个 jar 保持独立,Spring 那些同名的
META-INF/spring.factories、spring.handlers、META-INF/services/*等文件不会互相覆盖——这一点比胖 jar 安全。
二、Maven 插件方式(推荐)
用 maven-dependency-plugin 把依赖复制到 lib,再用 maven-jar-plugin 打主 jar 并在 manifest 写好 Class-Path。效果和 IDEA 那套一样,但可复现、进版本控制、CI 可用。
1 | |
关于 spring-boot-maven-plugin
如果项目里还启用了 spring-boot-maven-plugin 的 repackage,它默认会把产物重打成胖 jar,会覆盖上面瘦 jar 的效果。两种处理:
- 直接移除/不绑定
spring-boot-maven-plugin的repackagegoal; - 或保留它但跳过:
1 | |
打包与运行
1 | |
配置文件可以外置到 jar 同级目录,用参数指定:
1 | |
三、两种方式对比
| 维度 | IDEA Artifacts | Maven 插件 |
|---|---|---|
| 是否可复现 | ❌ 手动 GUI | ✅ 进版本控制 |
| CI/CD 友好 | ❌ | ✅ |
| 配置成本 | 一次次手点,易错 | 一次配置,长期复用 |
| 依赖分离 | ✅ | ✅ |
| 是否懂 Spring Boot 布局 | ❌ 通用 JAR | ✅(绕过 repackage,自己控制) |
小结
两种方式都能做到”瘦 jar + 依赖分离”,但 IDEA Artifacts 适合临时、一次性的场景,长期项目强烈建议用 Maven 插件方案:可复现、可进 CI、团队协作不踩坑。Gradle 同理,可用 Jar 任务配置 manifest 的 Class-Path 加上一个 Copy 任务复制依赖实现等价效果。