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,不依赖构建工具。

操作步骤

  1. 确保有一个带 main 方法的启动类(即 @SpringBootApplication 主类)。

  2. 菜单 File > Project Structure > Artifacts

  3. +JARFrom Module with dependencies

  4. 弹窗里设置导出信息:

    • Main Class 选你自己的启动类;
    • MANIFEST.MF 的目录不要用默认值,建议设置成项目根目录(默认值经常导致路径不对)。
  5. 关于 “JAR files from libraries” 的两个选项:

    选项 效果
    extract to the target JAR 打成一个胖 jar(依赖解压进主 jar)
    copy to the output directory and link via manifest 主 jar + 外部依赖 jar,通过 MANIFEST.MFClass-Path 链接 ← 依赖分离选这个
  6. 勾上 include in project build,设置好 Output directoryOK

  7. 菜单 Build > Build Artifacts > 选中目标 > Build,到 Output directory 即可看到 jar 和依赖。

这种方式的坑

  1. 不可复现:纯手点,配置不进版本控制,换机器/换人要重配。
  2. Class-Path 是相对路径:运行时 lib 目录必须和主 jar 保持相同相对位置,挪动就启动失败。
  3. 不理解 Spring Boot 布局:IDEA 生成的是通用 JAR,没有 BOOT-INFMain-Class 必须手动指向你自己的启动类,而不是 Spring 的 JarLauncher
  4. 资源/配置易漏application.yml 等是否打进去、是否外置,都要手动确认。

一个反而是优点的地方:依赖分离后,每个 jar 保持独立,Spring 那些同名的 META-INF/spring.factoriesspring.handlersMETA-INF/services/* 等文件不会互相覆盖——这一点比胖 jar 安全。

二、Maven 插件方式(推荐)

maven-dependency-plugin 把依赖复制到 lib,再用 maven-jar-plugin 打主 jar 并在 manifest 写好 Class-Path。效果和 IDEA 那套一样,但可复现、进版本控制、CI 可用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<build>
<plugins>
<!-- 1) 把依赖复制到 target/lib -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-deps</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

<!-- 2) 主 jar 只含自己的 class,manifest 里写 Class-Path 指向 lib/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.example.YourApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

关于 spring-boot-maven-plugin

如果项目里还启用了 spring-boot-maven-pluginrepackage,它默认会把产物重打成胖 jar,会覆盖上面瘦 jar 的效果。两种处理:

  • 直接移除/不绑定 spring-boot-maven-pluginrepackage goal;
  • 或保留它但跳过:
1
2
3
4
5
6
7
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>

打包与运行

1
2
3
mvn clean package
# 运行时 target/lib 要和主 jar 保持相对位置
java -jar target/your-app.jar

配置文件可以外置到 jar 同级目录,用参数指定:

1
java -jar target/your-app.jar --spring.config.location=file:./application.yml

三、两种方式对比

维度 IDEA Artifacts Maven 插件
是否可复现 ❌ 手动 GUI ✅ 进版本控制
CI/CD 友好
配置成本 一次次手点,易错 一次配置,长期复用
依赖分离
是否懂 Spring Boot 布局 ❌ 通用 JAR ✅(绕过 repackage,自己控制)

小结

两种方式都能做到”瘦 jar + 依赖分离”,但 IDEA Artifacts 适合临时、一次性的场景,长期项目强烈建议用 Maven 插件方案:可复现、可进 CI、团队协作不踩坑。Gradle 同理,可用 Jar 任务配置 manifest 的 Class-Path 加上一个 Copy 任务复制依赖实现等价效果。


Spring Boot 打包瘦身:依赖分离的两种方式(IDEA Artifacts vs Maven 插件)
http://eevann.cn/2026/06/16/springboot-jar-separate-dependencies/
作者
月下独白
发布于
2026年6月16日
许可协议