如何正确配置 Maven Shade 插件以生成可执行 Fat JAR

来源:建站技术作者:泰国程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何正确配置 Maven Shade 插件以生成可执行 Fat JAR》,敬请观看详情。把 Spring Boot 之外的普通 Java 项目打成可双击运行的可执行包时,依赖散落一地总让人头疼。Maven Shade 插件通过把全部依赖字节码合并进单一归档并重写清单文件,能直接产出 Fat JAR。但默认配置常因没有指定 Main-Class 或资源文件冲突而启动失败。正确做法是在 build 节点声明 shade 插件,利用 manifest 配置主入口,并用 transformer 处理 META-INF 下的服务描述与多份同名配置。掌握依赖最小化、排除签名文件以及用 relocate 解决包名冲突,才能稳定生成体积合理且可执行的胖包。

在 Java 项目交付时,将编译产物及全部第三方依赖打包成单一可执行文件,是简化部署的常见做法。Maven Shade 插件不同于 assembly,它能在字节码层面合并依赖并重新定位类路径,从而避免传统依赖拷贝带来的 CLASSPATH 混乱。理解其配置结构,是生成稳定 Fat JAR 的前提。

如何正确配置 Maven Shade 插件以生成可执行 Fat JAR

Shade 插件的基础配置结构

Maven Shade 插件需要在 pom.xml 的 build/plugins 节点中声明,并通过 execution 绑定到 package 阶段。最核心的任务是告诉插件哪些依赖要打进去、入口类是谁,以及如何处理依赖中的重复资源。

一个最小可运行的配置通常包含 manifest 的 Main-Class 指定,以及可选的 artifactSet 过滤。如果遗漏 Main-Class,生成的 JAR 虽然包含全部类,但系统无法识别启动点,运行 java -jar 时会报找不到主清单属性。下面给出基础模板:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.5.0</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <transformers>
              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>com.demo.App</mainClass>
              </transformer>
            </transformers>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

上述配置中,ManifestResourceTransformer 负责把 mainClass 写入 META-INF/MANIFEST.MF。执行 mvn package 后,target 下会同时出现原始瘦包和带 shaded 后缀的胖包,后者即可直接执行。

需要注意,Shade 默认不会覆盖已存在的相同名称资源,比如多个依赖都包含 META-INF/spring.factories,这时必须用 ServicesResourceTransformer 或 AppendingTransformer 来合并,否则部分框架的自动配置会失效。

处理依赖冲突与资源合并

当项目引入多个库,而这些库又依赖同一组件的不同版本,或者包含同路径的配置文件时,直接打包会导致文件互相覆盖。Shade 提供了 transformer 机制来解决这类问题。

以 Java SPI 机制为例,各依赖可能在 META-INF/services 下声明同一个接口的不同实现类。使用 ServicesResourceTransformer 可以把它们拼接成一份完整服务文件,而不是随机保留其中一个。配置方式如下:

<configuration>
  <transformers>
    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
      <mainClass>com.demo.App</mainClass>
    </transformer>
    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
  </transformers>
</configuration>

对于普通的文本配置,例如 license 文件或自定义的 properties,可以使用 AppendingTransformer 并指定资源路径,让内容纵向追加。这样不会丢失任何一方的配置信息,也避免人工干预。

另一个常见坑是签名文件。若依赖带有 META-INF/*.SF、*.DSA 等签名,合并后 JVM 校验会失败。可通过 filters 排除这些文件:

<configuration>
  <filters>
    <filter>
      <artifact>*:*</artifact>
      <excludes>
        <exclude>META-INF/*.SF</exclude>
        <exclude>META-INF/*.DSA</exclude>
        <exclude>META-INF/*.RSA</exclude>
      </excludes>
    </filter>
  </filters>
</configuration>

使用 relocate 解决包名冲突

某些情况下,两个依赖各自内嵌了不同版本的同一工具库,且都暴露了公开 API。直接合并会出现类重复定义,甚至引发 NoSuchMethodError。Shade 的 relocate 功能可以对指定包路径做字节码重写,相当于给类搬个家。

例如把依赖中的 org.apache.commons 重定位到 com.demo.shaded.commons,就能和另一份原生 commons 共存。配置如下:

<configuration>
  <relocations>
    <relocation>
      <pattern>org.apache.commons</pattern>
      <shadedPattern>com.demo.shaded.commons</shadedPattern>
    </relocation>
  </relocations>
</configuration>

relocate 会在打包时扫描所有相关 class 文件,把内部的 import 和类名引用同步改写,因此对运行时代码透明。缺点是会增加包体积,并且调试时堆栈中的类名是重写后的,需要对照映射。

建议只对确实冲突的包做 relocate,而不是全量重定位,否则后续排查问题成本较高。配合 artifactSet 精确圈定要打进来的依赖,能进一步减小 Fat JAR 的大小。

完整示例与验证方式

综合前面的要点,一个较完整的 Shade 配置应当包含主类、服务合并、签名排除和必要的重定位。下面给出可直接套用的片段:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.5.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals><goal>shade</goal></goals>
      <configuration>
        <artifactSet>
          <includes>
            <include>com.google.guava:guava</include>
            <include>org.slf4j:slf4j-api</include>
          </includes>
        </artifactSet>
        <filters>
          <filter>
            <artifact>*:*</artifact>
            <excludes>
              <exclude>META-INF/*.SF</exclude>
              <exclude>META-INF/*.DSA</exclude>
            </excludes>
          </filter>
        </filters>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.demo.App</mainClass>
          </transformer>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

打包完成后,进入 target 目录,执行 java -jar 项目名称-版本-shaded.jar。若控制台正常打印预期日志,说明配置生效。也可用 jar tf 命令列出内容,确认依赖类都在根包下而非 BOOT-INF 这类子目录中。

当项目后续引入新依赖,记得检查是否带来了同名资源或签名文件。保持配置中的过滤器与 transformer 与实际依赖同步,才能保证每次构建出的 Fat JAR 都可执行且行为一致。

Maven_Shade Fat_JAR executable_jar修改时间:2026-08-07 14:54:57

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。