深入解析:如何修复Maven打包后缺失主清单属性的JAR文件
1. 从一次“跑不起来”的打包说起那天下午我正喝着咖啡准备把刚写完的一个Java小工具打个包发给同事用。项目是用Maven管理的我熟练地在终端里敲下mvn clean package看着一行行日志飞过最后显示“BUILD SUCCESS”。我心想稳了。于是我找到生成的myapp-1.0-SNAPSHOT.jar文件双击运行或者更专业点在命令行里输入java -jar myapp-1.0-SNAPSHOT.jar。结果屏幕上冷冰冰地抛出一行错误myapp-1.0-SNAPSHOT.jar中没有主清单属性相信很多Java开发者尤其是刚接触Maven打包的朋友都遇到过这个经典的“拦路虎”。那一刻的感觉就像你配好了所有零件拧紧了最后一颗螺丝却发现发动机点不着火——东西都在但就是启动不了。这个错误的核心其实就是生成的JAR包“迷路”了它不知道自己该从哪个“门”主类进去启动程序。那么这个神秘的“主清单属性”到底是什么简单来说一个可执行的JAR包它的根目录下都有一个META-INF/MANIFEST.MF文件。这个文件就像这个JAR包的“身份证”和“说明书”里面记录了很多元数据信息。其中最关键的一行就是Main-Class它指明了当你用java -jar命令运行这个包时Java虚拟机应该去执行哪个类里的main方法。如果这个属性缺失了java -jar命令就懵了不知道从何下手于是报出“没有主清单属性”的错误。Maven作为一个强大的构建工具默认的打包插件maven-jar-plugin生成的普通JAR包是不包含这个Main-Class属性的因为它默认你打的可能是一个供其他项目依赖的库Library而不是一个可独立运行的应用程序。所以当我们需要一个可执行JAR时就必须明确地告诉Maven“嘿请把主类信息写进清单里。” 接下来我就结合自己踩过的坑和总结的经验分场景详细说说怎么搞定它。2. 核心修复方案两大插件详解修复这个问题的核心就是通过Maven插件在打包过程中向MANIFEST.MF文件正确写入Main-Class属性。根据你的项目类型主要会用到两个插件spring-boot-maven-plugin和maven-shade-plugin。它们虽然都能解决问题但设计初衷和适用场景有很大不同。2.1 方案一Spring Boot项目的“御用”方案如果你的项目是基于Spring Boot的那么恭喜你解决方案通常是最简单的。Spring Boot提供了一站式的打包方案它的核心就是spring-boot-maven-plugin插件。为什么是它这个插件做的远不止指定主类那么简单。它会打出一个特殊的“fat jar”或“uber jar”也就是把所有依赖的第三方库包括内嵌的Tomcat等Web容器都打包进同一个JAR文件里形成一个完全自包含、可以直接用java -jar运行的独立应用。它的“魔力”在于会自动定位你的主类通常是带有SpringBootApplication注解的类。具体怎么配在你的pom.xml文件的buildplugins部分加入以下配置就基本足够了build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build是的就这么简单连版本号都可以不指定继承自Spring Boot父工程。执行mvn clean package后你会在target目录下找到两个JAR文件一个是普通的*.jar另一个是*-exec.jar或直接就是可执行的fat jar取决于插件版本。运行那个可执行的JAR即可。我踩过的坑有时候项目结构比较特别比如主类不在默认的扫描路径下或者你有多个main方法。这时插件可能无法自动识别。别慌我们可以手动指定plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration mainClasscom.yourcompany.yourapp.Application/mainClass /configuration /plugin另外记得检查你的启动类是否正确地使用了SpringBootApplication注解。我曾经有一次不小心把注解写错了导致插件虽然打包了但运行时依然找不到合适的入口那感觉真是排查到怀疑人生。2.2 方案二普通Java项目的“万能钥匙”对于非Spring Boot的普通Java项目比如一个简单的Swing桌面应用、一个工具类集合或者一个传统的Java SE应用我们通常使用maven-shade-plugin。这个插件功能非常强大除了能处理清单文件最主要的功能是“打包依赖”创建uber jar并且能处理依赖冲突时资源文件的合并问题。配置详解下面是一个最常用的配置模板你可以直接拷贝并根据注释修改build plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-shade-plugin/artifactId version3.5.0/version !-- 建议使用较新版本 -- executions execution phasepackage/phase !-- 绑定到package生命周期阶段 -- goals goalshade/goal !-- 执行shade目标 -- /goals configuration transformers !-- 专门用于处理MANIFEST.MF的转换器 -- transformer implementationorg.apache.maven.plugins.shade.resource.ManifestResourceTransformer !-- 在这里指定你的主类全限定名 -- mainClasscom.example.myapp.Main/mainClass /transformer /transformers !-- 可选指定最终生成的JAR文件名去掉版本号等 -- finalNamemy-awesome-app/finalName /configuration /execution /executions /plugin /plugins /build关键点解析版本建议使用较新的版本如3.5.0老版本可能有一些已知的Bug。execution这部分配置将插件的shade目标绑定到Maven的package阶段。这样当你执行mvn package时它会自动执行。transformerManifestResourceTransformer是实现清单信息写入的关键。在它的配置里用mainClass标签明确指定主类。finalName这个配置可以让你定制输出JAR的名字比如去掉繁琐的版本号和-SNAPSHOT后缀让最终文件更简洁。一个真实的例子假设你的项目结构里主类位于src/main/java/com/example/tool/AppLauncher.java并且这个类里有一个标准的public static void main(String[] args)方法。那么上面的mainClass就应该写为mainClasscom.example.tool.AppLauncher/mainClass。配置好后运行mvn clean package在target目录下生成的my-awesome-app.jar就是一个可以直接用java -jar运行的可执行文件了。3. 进阶排查与深度避坑指南解决了基本配置问题有时候我们还会遇到一些“诡异”的情况。明明配置看起来没错为什么还是报错呢这一部分我们来深入排查。3.1 验证与排查你的MANIFEST.MF对了吗配置完插件打包成功后第一件该做的事不是直接运行而是先“验货”。怎么验查看生成的JAR包里的META-INF/MANIFEST.MF文件。方法一使用命令行工具在终端里使用jar命令JDK自带来查看jar tf your-application.jar | grep META-INF/MANIFEST.MF # 先确认文件存在 jar xf your-application.jar META-INF/MANIFEST.MF # 解压出清单文件 cat META-INF/MANIFEST.MF # 查看内容或者更直接地用vim或less查看vim your-application.jar在vim中你可以像浏览目录一样找到并打开META-INF/MANIFEST.MF文件。方法二使用压缩软件直接用WinRAR、7-Zip等软件打开JAR文件它本质上就是个ZIP压缩包找到META-INF/MANIFEST.MF拖出来用文本编辑器打开。看什么打开文件后你应该能看到类似这样的内容以Spring Boot项目为例Manifest-Version: 1.0 Spring-Boot-Version: 2.7.10 Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.yourcompany.yourapp.Application ...注意对于Spring Boot的fat jarMain-Class指向的是Spring Boot自带的JarLauncher而真正的应用主类写在Start-Class属性里。这是正常的而对于使用maven-shade-plugin的普通项目你应该直接看到Main-Class: com.example.myapp.Main。如果这个文件里根本没有Main-Class属性或者属性的值和你预期的不一样那就说明插件配置没有生效需要回头检查你的pom.xml。3.2 常见陷阱与解决方案插件冲突你的pom.xml里可能配置了多个会修改清单文件的插件比如同时有maven-jar-plugin和maven-shade-plugin且配置了不同的Main-Class。这可能会导致覆盖或冲突。通常如果你用了shade插件就不需要再单独配置maven-jar-plugin的archive部分来设置清单了。检查并精简插件配置。生命周期绑定错误确保maven-shade-plugin的execution正确绑定到了package阶段。如果绑定错了阶段比如compile打包时就不会执行。主类名写错这是最常犯的低级错误。检查mainClass标签里的值是否是你的主类全限定名包名类名并且这个类必须存在且拥有public static void main方法。大小写敏感一个字母都不能错。依赖范围问题如果你在打包时遇到ClassNotFoundException即使主类找到了也可能是因为依赖没打进去。对于maven-shade-plugin确保你的依赖项scope不是provided或test。provided范围的依赖如Servlet API默认不会被打进uber jar。多模块项目在Maven多模块项目中你通常是在父模块中声明插件但在子模块中执行打包。要特别注意插件的配置是否被正确继承或者你是否需要在具体的子模块中重新配置。有时在子模块的pom.xml中显式配置一遍更稳妥。4. 其他场景与备选方案除了上述两大主流方案根据项目的特殊需求还有其他一些工具和思路可以解决主清单属性问题。4.1 使用 maven-jar-plugin 直接配置如果你的项目非常简单没有第三方依赖或者你希望依赖的JAR包放在外部通过-cp指定类路径那么你可以直接使用Maven自带的maven-jar-plugin来设置主类而不需要打一个包含所有依赖的“胖JAR”。配置如下plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId version3.3.0/version configuration archive manifest addClasspathtrue/addClasspath !-- 可选在清单中添加Class-Path -- classpathPrefixlib//classpathPrefix !-- 可选指定依赖库目录 -- mainClasscom.example.myapp.Main/mainClass /manifest /archive /configuration /plugin这种方式生成的JAR文件很小只包含你自己的编译类。运行时你需要确保所有依赖的JAR包都在lib/目录下或-cp指定的路径中。对于分发和部署你需要把主JAR和一堆依赖库一起打包不如一个独立的fat jar方便。4.2 使用 maven-assembly-pluginmaven-assembly-plugin是另一个功能强大的打包插件它可以创建更复杂的发布包比如包含二进制文件、脚本、文档等的ZIP或TAR包。当然它也可以用来创建带有主清单属性的可执行JAR。它的配置比shade插件更复杂一些需要定义一个assembly descriptorXML文件来描述打包的格式和内容。对于只是需要指定主类的场景有点“杀鸡用牛刀”的感觉。但如果你需要定制化的打包结构例如生成一个包含启动脚本、配置文件和应用JAR的发布包它是个不错的选择。4.3 在IDE中直接运行 vs. 打包后运行这里有一个非常重要的概念区分。在IntelliJ IDEA或Eclipse等IDE中你直接点击“运行”按钮能成功是因为IDE智能地构建了项目的类路径Classpath它知道你的主类在哪里以及所有依赖库在哪里。这不等于你的打包配置是正确的。我见过不少新手朋友在IDE里运行得好好的一打包就报“没有主清单属性”然后非常困惑。记住IDE的运行环境和最终通过mvn package生成的、交付给其他机器运行的JAR包是两套不同的机制。打包配置pom.xml才是决定最终JAR包能否独立运行的关键。所以养成习惯开发测试阶段就定期用mvn clean package java -jar target/xxx.jar来验证你的打包结果而不是仅仅依赖IDE的运行按钮。说到底修复“没有主清单属性”这个问题本质上就是和Maven的构建生命周期和插件机制打交道。理解了MANIFEST.MF文件的作用知道了spring-boot-maven-plugin和maven-shade-plugin这两个核心插件的用法这个问题就再也难不倒你了。下次再遇到不妨先冷静下来打开那个JAR包看看它的“身份证”上到底缺了什么然后对症下药精准配置。

相关新闻

iOS 应用的 HTTPS 连接端口在网络抓包调试中有什么作用

iOS 应用的 HTTPS 连接端口在网络抓包调试中有什么作用

在网络调试中,经常会看到这样的信息: https://api.example.com:443 https://api.example.com:8443很多人看到端口时只知道 443 是 HTTPS,但在实际抓包过程中,端口信息可能比 URL 更重要。 简单的例子: App 请求已经发出…

2026/5/17 11:23:54 阅读更多 →
2026年03月09日 AI前沿资讯日报 (周一)

2026年03月09日 AI前沿资讯日报 (周一)

2026年03月09日 AI前沿资讯日报 (周一)每天早间5分钟,帮你掌握昨日AI行业最新动态今日AI要闻 1. AI对老师的影响 AI技术持续发展,各厂商在应用层持续创新落地。 来源: 微博热搜 2. OpenAI多位负责人抗议辞职 OpenAI持续引领大模型发展,最新版…

2026/5/17 11:23:54 阅读更多 →
Fish-Speech-1.5多模态交互:结合视觉与语音的智能应用

Fish-Speech-1.5多模态交互:结合视觉与语音的智能应用

Fish-Speech-1.5多模态交互:当语音合成“看见”世界 想象一下,你走进一个智能展厅,墙上的屏幕显示着一幅宁静的山水画。你驻足欣赏,脸上露出微笑。这时,一个温和的声音在你耳边响起:“这幅画描绘了清晨的山…

2026/7/3 10:26:39 阅读更多 →

最新新闻

ReScript genType 实战案例:电商平台前端架构中的类型安全实践 [特殊字符]

ReScript genType 实战案例:电商平台前端架构中的类型安全实践 [特殊字符]

ReScript genType 实战案例:电商平台前端架构中的类型安全实践 🛒 【免费下载链接】genType Auto generation of idiomatic bindings between Reason and JavaScript: either vanilla or typed with TypeScript/FlowType. 项目地址: https://gitcode.c…

2026/7/4 21:24:00 阅读更多 →
如何自定义Cosmos-Transfer1-DiffusionRenderer:从模型权重到推理参数的高级配置

如何自定义Cosmos-Transfer1-DiffusionRenderer:从模型权重到推理参数的高级配置

如何自定义Cosmos-Transfer1-DiffusionRenderer:从模型权重到推理参数的高级配置 【免费下载链接】cosmos-transfer1-diffusion-renderer Cosmos-Transfer1-DiffusionRenderer: High-quality video de-lighting and re-lighting based on Cosmos video diffusion fr…

2026/7/4 21:21:59 阅读更多 →
opmsg高级功能:Cc/Bcc支持、密钥链接和会话密钥管理

opmsg高级功能:Cc/Bcc支持、密钥链接和会话密钥管理

opmsg高级功能:Cc/Bcc支持、密钥链接和会话密钥管理 【免费下载链接】opmsg opmsg message encryption 项目地址: https://gitcode.com/gh_mirrors/op/opmsg opmsg是一款专注于消息加密的工具,提供了强大的安全通信能力。本文将深入介绍opmsg的三…

2026/7/4 21:19:58 阅读更多 →
豆包vs文心一言:中文AI助手选型实战指南

豆包vs文心一言:中文AI助手选型实战指南

1. 这不是“选软件”,而是选一个适配你工作流的智能协作者“豆包和文心这二个软件哪个更好?”——这句话我每天在技术社区、内容创作群、甚至公司内部培训现场听到不下十次。但每次听到,我都会先反问一句:你打算用它来干什么&…

2026/7/4 21:19:58 阅读更多 →
SQL CTE(公用表表达式)用法:SQL Ultimate Course复杂查询简化

SQL CTE(公用表表达式)用法:SQL Ultimate Course复杂查询简化

SQL CTE(公用表表达式)用法:SQL Ultimate Course复杂查询简化 【免费下载链接】sql-ultimate-course The most comprehensive SQL guide from a real-world expert! Learn everything from basics to advanced queries, optimizations, and real-world SQL 项目地…

2026/7/4 21:17:58 阅读更多 →
Mongood JSON Schema编辑器:轻松实现数据验证与规范化

Mongood JSON Schema编辑器:轻松实现数据验证与规范化

Mongood JSON Schema编辑器:轻松实现数据验证与规范化 【免费下载链接】mongood A MongoDB GUI with Fluent Design 项目地址: https://gitcode.com/gh_mirrors/mo/mongood Mongood是一款采用Fluent Design设计的MongoDB GUI工具,其内置的JSON Sc…

2026/7/4 21:17:57 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻