
本文详解为何 maven-shade-plugin 未生效的常见原因——误将插件声明置于 <pluginManagement> 中,并提供完整、可落地的配置方案,确保 mvn package 正确触发 Shade 插件构建包含依赖的可运行 JAR。
本文详解为何 `maven-shade-plugin` 未生效的常见原因——误将插件声明置于 `
在多模块 Maven 项目中,若希望为特定子模块(如 simple-client 或 simple-server)生成包含所有运行时依赖的「Fat Jar」(即 Uber JAR),maven-shade-plugin 是最常用且可靠的工具。但实践中常出现「执行 mvn package 后却只生成普通 JAR(由 maven-jar-plugin 生成),Shade 插件完全未执行」的问题——这并非插件版本或生命周期冲突所致,而是一个典型的配置作用域误解。
? 根本原因:<pluginManagement> ≠ <plugins>
Maven 中:
- <pluginManagement> 仅用于集中声明插件的默认配置和版本,它本身不会绑定插件到生命周期,也不会触发执行;
- <build><plugins>(即顶层 plugins 块)才真正将插件声明“激活”,使其在对应 phase(如 package)中运行。
在你的 simple-client/pom.xml 中,Shade 插件被错误地放在 <pluginManagement> 内:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<!-- ... -->
</plugin>
</plugins>
</pluginManagement>
</build>✅ 正确做法是:移出 <pluginManagement>,直接置于 <build><plugins> 下:
<build>
<finalName>Server</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.firstproject.myapp.AppServer</mainClass>
</transformer>
</transformers>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<dependencyReducedPomLocation>${java.io.tmpdir}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
<relocations>
<relocation>
<pattern>com.firstproject.myapp</pattern>
<shadedPattern>hidden.coyote</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>? 提示:<finalName> 仍保留在 <build> 根层级下,它影响最终 JAR 文件名(如生成 Server.jar 而非默认的 simple-client-1.0-SNAPSHOT.jar)。
✅ 验证与最佳实践
验证是否生效:执行 mvn clean package -X(开启 debug 日志),搜索 maven-shade-plugin:3.4.1:shade,确认其出现在 package phase 日志中;同时检查 target/ 目录下是否生成了 Server.jar(而非 Server-1.0-SNAPSHOT.jar)及 Server-original.jar(原始 jar)。
避免父 POM 干预:你当前的 parent-project 使用 packaging=pom 且 <build> 为空,这是推荐做法——父 POM 不应定义具体插件行为,子模块按需独立声明。若未来需统一 Shade 配置(如所有可执行模块共用相同 mainClass 模式),可在父 POM 的 <pluginManagement> 中预设,但每个子模块仍必须在自身 <plugins> 中显式引用该插件:
<!-- 父 POM 中(仅管理) -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</plugin>
</plugins>
</pluginManagement><!-- 子模块中(必须显式启用) -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<!-- 版本继承自 pluginManagement,无需重复声明 -->
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.firstproject.myapp.AppServer</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>⚠️ 注意事项总结
- ❌ 不要仅靠 <pluginManagement> “以为已配置” —— 它不执行,只管理;
- ✅ <plugins> 是插件执行的唯一入口,必须出现在子模块 pom.xml 的 <build> 直接子节点中;
- ? maven-jar-plugin 的默认 jar goal 总会在 package phase 执行,但只要 Shade 插件正确绑定,它会生成额外的 shaded jar(原 jar 仍存在,除非显式禁用);
- ? 若仍不生效,请检查 mvn help:effective-pom -Dverbose 查看实际生效的 POM 结构,确认 Shade 插件是否出现在 <plugins> 列表中。
遵循以上配置逻辑,即可稳定、可靠地为任意子模块生成带主类、含全部依赖的可执行 Fat Jar。

















