资讯详情

IDEA打包JAR包全攻略:从普通JAR到可执行JAR,含常见报错排查

📅 2026/9/24 19:14:56 | 华诺云谱 👁 阅读
IDEA打包JAR包全攻略:从普通JAR到可执行JAR,含常见报错排查
1. 项目概述1.1 为什么你需要学会用IDEA打JAR包先聊点实在的。我在日常工作中经常被同事问到“我这个Java项目在IDEA里跑得好好的怎么发给别人就跑不起来了”或者是“我明明把项目打成了JAR包双击却没反应到底是哪里出了问题”这些问题本质上都指向同一个东西用IDEA把Java项目打包成JAR。不管你是刚学Java的初学者还是已经写了几年业务代码的开发者只要你的代码需要脱离开发环境运行或者说需要交付给部署人员、需要放到服务器上执行就必须学会这步操作。先说清楚JAR包是什么。JAR的全称是Java Archive翻译过来就是Java归档文件。你可以把它理解成一个压缩包但这个压缩包里装的不是普通文件而是编译后的.class字节码文件、资源文件、配置文件还有可选的元数据。Java虚拟机可以直接加载这个包里的类来运行程序。很多人觉得打包是件很简单的事点一下Build按钮就完事了。但真正落地的时候你会遇到各种问题普通JAR包和可执行JAR包的区别是什么为什么打出来的包运行时报“找不到主类”第三方依赖到底有没有被打进去别人拿到你的JAR包后怎么运行最方便这篇文章不绕弯子直接从IDEA实际操作出发把普通JAR包和可执行JAR包的完整打包过程、Maven项目的打包方式、常见报错的排查思路全部讲透。适合所有用IDEA开发Java项目的开发者不管你是学生、刚入职的新人还是想规范交付流程的老手这篇文章都能给你一套能直接复用的方案。1.2 我踩过的那些坑希望你别再踩先说一个很典型的场景。去年有个同事从网上找了一个开源项目用IDEA打开后编译、运行都很正常。结果他想把项目发给另一个同事做接口联调就随手在IDEA里点了File → Project Structure → Artifacts把项目打成了一个JAR包。对面同事拿到包后执行java -jar xxx.jar直接报错no main manifest attribute, in xxx.jar。这个报错信息很经典背后的原因也很有代表性IDEA默认帮你创建的Artifacts只是一个普通的JAR包它不会自动帮你指定主类入口也就是MANIFEST.MF文件里的Main-Class属性是空的。我当时帮他排查时发现他在打包时根本没有去Project Structure里配置Main-Class只是默认生成了一个空的MANIFEST.MF文件。这个问题的本质就是对IDEA打包机制不熟悉把“打JAR包”和“打可执行JAR包”混为一谈了。所以这篇文章我打算从底层逻辑讲起先把JAR包的内部结构说清楚再一步步演示操作。这样你遇到问题的时候至少知道去哪个环节排查而不至于两眼一抹黑。2. JAR包的基本结构2.1 揭开JAR包的神秘面纱JAR包本质上就是一个ZIP格式的压缩文件只是扩展名换成了.jar。你用任何解压工具都能打开它。一个典型的JAR包内部结构大致如下xxx.jar ├── META-INF/ │ ├── MANIFEST.MF │ └── ... ├── com/ │ └── example/ │ ├── MainClass.class │ └── ... ├── resources/ │ ├── application.yml │ └── ... └── ...其中最关键的是META-INF/MANIFEST.MF这个文件。它记录了这个JAR包的元信息包括版本号、创建工具、类路径以及最重要的Main-Class属性。举个例子一个可执行JAR包的MANIFEST.MF文件内容大致是这样的Manifest-Version: 1.0 Main-Class: com.example.MainClass如果你用记事本打开一个打包好的JAR包里的MANIFEST.MF文件看到的内容基本就是这种格式。Main-Class这一行的值就是Java虚拟机运行这个JAR包时要加载的入口类。2.2 普通JAR包与可执行JAR包的区别很多初学者分不清这两种JAR包这里我直接用最直白的话解释普通JAR包只是一种分发和归档的格式它本身没有明确的运行入口。你可以把它当作依赖库引入到其他项目中也可以把它解压出来查看内容但你不能直接双击运行它也不能用java -jar命令启动它。如果你用java -jar去运行一个没有配置Main-Class的JAR包就会报我们刚才说的那个经典错误。可执行JAR包在普通JAR包的基础上额外在MANIFEST.MF文件里指定了Main-Class有时还会指定Class-Path来声明运行所需的依赖。只有这种JAR包才能用java -jar命令直接运行。这两个概念的本质差别就是MANIFEST.MF文件里有没有Main-Class这一个属性。在IDEA里打JAR包时你首先要搞清楚一个问题你打的这个包是给别人当依赖库用的还是要能独立运行的程序两者的操作配置完全不一样。下面我会分场景详细演示。3. 环境准备与前置条件3.1 JDK安装与IDEA配置打JAR包的前提是你本机已经装好了JDK并且IDEA能正常编译运行Java项目。JDK的安装这里不展开讲但有个核心点必须要提IDEA使用的JDK版本和项目实际需要的JDK版本必须匹配。如果你项目用的是Java 8的语法特性但IDEA里配置的是JDK 17编译时虽然大概率能过但运行环境如果是Java 8就会直接报UnsupportedClassVersionError——这个问题我在工作中见得非常多。检查IDEA里项目JDK配置的方法很简单打开IDEA按快捷键CtrlAltShiftS打开Project Structure窗口。在左侧选择Project右侧的Project SDK就能看到当前项目使用的JDK版本。确认Language Level与SDK版本匹配。IDEA下载和安装方面网上资源很多但我不建议你去搞什么破解版。IDEA社区版完全够用而且免费功能上除了部分企业级框架的专门支持外日常的Java开发、打包、调试都没问题。JetBrains官网直接下载即可。3.2 确认项目结构是否规范在打包之前你需要确认项目的基本目录结构是规范的。一个标准的IDEA Java项目结构通常是这样的my-project/ ├── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── MainClass.java │ └── resources/ │ └── application.properties ├── out/ │ └── production/ │ └── my-project/ ├── .idea/ └── pom.xml (如果是Maven项目)其中src/main/java目录存放Java源码src/main/resources目录存放资源文件out/production目录是IDEA默认的编译输出目录也就是.class文件生成的地方。这一步看起来很基础但很多打包问题其实都出在项目结构不规范上。比如有的人把源码直接放在项目根目录下而没有放在src目录里那IDEA在编译时可能根本找不到源码打出来的JAR包自然是空壳。4. 在IDEA中打包非Maven项目的JAR包4.1 场景说明非Maven项目也就是我们常说的普通Java项目没有pom.xml文件纯粹靠IDEA的编译器来编译和打包。这种项目在初学阶段很常见也适合用来理解JAR包打包的本质过程。4.2 步骤一编译项目确保代码无报错在打包之前务必先编译整个项目保证没有编译错误。我见过有人连编译都没通过下面的Build Artifacts按钮都是灰色的还一直在问为什么点不了。编译操作的入口有两个菜单栏Build → Rebuild Project。快捷键CtrlF9。执行后观察IDEA底部的Build窗口确保显示Build completed successfully。此时out/production目录下会生成对应模块的.class文件。提示Rebuild Project会强制重新编译所有源码而不是只编译变更过的文件。在打包之前做一次全量编译是最稳妥的可以避免因为部分类没有编译而导致JAR包缺失文件。4.3 步骤二配置ArtifactsArtifacts是IDEA里用来描述“打包产物如何生成”的配置项。简单理解你需要告诉IDEA要把哪些编译好的class文件、哪些资源文件、打包成什么格式、入口类是谁。操作路径如下快捷键CtrlAltShiftS打开Project Structure窗口。左侧选择Artifacts点击号。选择JAR → From modules with dependencies。这里有个关键选择页面需要填几个字段Module选择你要打包的模块如果你的项目只有一个模块直接选默认的即可。Main Class点击右侧的文件夹图标选择你项目中的入口类也就是包含main方法的那个类。extract to the target JAR推荐选择此项。它的意思是将依赖库的class文件解压后和项目自身class文件放在一起。如果选择copy to the output directory and link via manifest则依赖不会被打进JAR包而是放在外部目录运行时会因为找不到依赖而报ClassNotFoundException。我已经在项目里建好了一个示例入口类com.example.MainClass这里面有一个标准的main方法。接下来直接选择它即可。4.4 步骤三打包并验证配置完成后点击OK关闭Project Structure窗口。发现菜单栏里出现了Build → Build Artifacts选项。点击后选择Build或者Rebuild。打包完成后IDEA会在项目的out/artifacts目录下生成JAR文件。此时我们要做两件事第一用压缩工具打开JAR包确认META-INF/MANIFEST.MF文件里包含Main-Class属性内容类似这样Manifest-Version: 1.0 Main-Class: com.example.MainClass第二打开命令行终端进入JAR包所在目录执行java -jar my-project.jar能正常输出程序的运行结果说明这个包是可用的。4.5 普通JAR包无主类怎么打如果你只需要把项目打成一个供其他人引入的依赖库不需要直接运行那就不需要指定Main-Class。操作上仍然是在Project Structure → Artifacts里新建一个JAR包但类型选择Empty。然后把你想要打包的编译输出目录添加进去即可。这种方式打出来的JAR包没有主类入口别人引用它的时候是通过import语法来使用里面的类而不是通过java -jar来运行。5. 在IDEA中打包Maven项目的JAR包5.1 Maven项目的特殊之处如果你是用Maven管理的项目项目根目录下会有pom.xml文件。相比普通Java项目Maven项目的打包方式更规范也更方便管理依赖。Maven项目打JAR包的方式有几种我强烈推荐用Maven生命周期命令而不是用IDEA的Artifacts功能。因为Maven项目用Artifacts打包时经常会遇到依赖缺失、构建环境不一致的问题而Maven自己打出来的包结构更标准也更容易排查问题。还有一个业界普遍使用的技巧用Spring Boot的Maven插件打可执行JAR包。Spring Boot的JAR包和普通JAR包有点不一样它会生成一个特殊的fat JAR把项目所有依赖全部塞进去同时使用自定义的类加载器来加载这些第三方类。这个后面再细说。5.2 用Maven生命周期打包如果在IDEA右侧的Maven面板看不到你可以通过View → Tool Windows → Maven打开。在Maven面板里展开项目模块的Lifecycle双击package命令Maven就会自动执行编译、测试、打包全流程。这个过程中Maven会执行clean清理旧的编译产物。执行compile编译源码。执行test运行单元测试。执行package将项目打包成JAR包。这个过程中最容易出现的问题就是测试不通过导致打包失败。如果只是临时打包不想执行测试可以在Lifecycle面板上方的执行命令处输入mvn package -DskipTests我个人的习惯是本机能正常跑测试的情况下先不要跳过测试。因为你不知道这次改动会不会引入回归问题跳过测试把包打出来到了测试环境再报错反而更浪费时间。但如果只是为了快速交付一个临时包跳过测试也无可厚非。打包完成后JAR包会生成在项目的target目录下文件名为项目名-版本号.jar。5.3 Maven打出的JAR包不可运行怎么处理这里有必要单独讲一下普通Maven项目用mvn package打出来的JAR包默认只是一个普通JAR包它不会把依赖打进包里也不会自动配置Main-Class属性。所以很多人在这一步会遇到明明打包成功了但执行java -jar却报错“找不到主清单属性”或“找不到类”。解决办法有两种方法一配置maven-assembly-plugin在pom.xml里加入以下插件配置build plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-assembly-plugin/artifactId version3.6.0/version configuration descriptorRefs descriptorRefjar-with-dependencies/descriptorRef /descriptorRefs archive manifest mainClasscom.example.MainClass/mainClass /manifest /archive /configuration executions execution idmake-assembly/id phasepackage/phase goals goalsingle/goal /goals /execution /executions /plugin /plugins /build配置完成后执行mvn clean package在target目录下会生成xxx-jar-with-dependencies.jar这个就是包含所有依赖的可执行JAR包。方法二使用Spring Boot Maven插件如果你的项目是基于Spring Boot的可以直接在pom.xml里配置spring-boot-maven-pluginbuild plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build之后执行mvn clean package生成的JAR包就是可执行的fat JAR直接java -jar即可运行。6. 操作实战与核心环节实现6.1 非Maven项目完整打包演示为了让大家看得更明白我用一个最简单的Java项目来做完整演示。项目结构如下demo-pack/ ├── src/ │ └── com/ │ └── example/ │ ├── MainClass.java │ └── GreetingService.javaMainClass.java内容package com.example; public class MainClass { public static void main(String[] args) { GreetingService service new GreetingService(); String message service.buildGreeting(打包测试); System.out.println(message); } }GreetingService.java内容package com.example; public class GreetingService { public String buildGreeting(String name) { return Hello, name !; } }我们按照前面的步骤操作第一步CtrlF9编译项目确认Build completed successfully。第二步CtrlAltShiftS打开Project Structure → Artifacts新建JAR包。第三步选择From modules with dependencies在Main Class位置选择com.example.MainClass。第四步点击OK关闭窗口然后Build → Build Artifacts → Build。此时在out/artifacts/demo_pack_jar目录下会生成demo-pack.jar。打开命令行执行java -jar demo-pack.jar输出结果Hello, 打包测试!这就是一个完整的打包流程是不是很简单6.2 带第三方依赖的项目打包实战上面的示例项目没有依赖任何第三方库打出来的包自然比较干净。但实际开发中项目几乎都会依赖第三方JAR包比如MySQL驱动、HttpClient、fastjson等。我先建一个需要依赖第三方库的演示项目用它来展示带依赖项目的打包全过程。测试代码里要使用fastjson来构造JSON字符串package com.example; import com.alibaba.fastjson.JSONObject; public class MainClass { public static void main(String[] args) { JSONObject obj new JSONObject(); obj.put(name, 打包测试); obj.put(type, 带依赖演示); System.out.println(obj.toJSONString()); } }在这个项目中fastjson是一个独立的外部依赖库我通过手动添加的方式引入到项目中。如果你用的是Maven项目不需要手动下载JAR包直接在pom.xml里声明依赖坐标即可。配置Artifacts的过程和之前一样在Project Structure → Artifacts → JAR → From modules with dependencies里设置Main Class。这里有一个非常关键的选项页面底部会有两个单选extract to the target JARcopy to the output directory and link via manifest我强烈推荐选择extract to the target JAR因为这样打出来的包是一个完整的fat JAR所有依赖都在里面发给任何人、放到任何机器上都能直接运行。第二种方式生成的JAR包体积很小但依赖在外部目录运行时需要额外设置Class-Path传播和使用都很麻烦。打包完成后你可以用解压工具打开JAR包在com/alibaba/目录下能看到fastjson的class文件说明依赖已经被正确打进包里了。然后执行java -jar demo-with-deps.jar看到输出结果{name:打包测试,type:带依赖演示}6.3 指定JAR包入口函数的特殊需求有时候依赖方会明确要求你提供一个JAR包而且程序入口不是标准的main方法签名或者一个JAR包里包含多个入口类需要用户自己指定执行哪个类。这种情况在IDEA里有几种处理方式方式一通过MANIFEST.MF指定主类如果你是用Artifacts打包重新进入Project Structure → Artifacts选择当前已有的Artifacts在Output Layout里右键点击META-INF目录选择Create Manifest。然后手动编辑MANIFEST.MFManifest-Version: 1.0 Main-Class: com.example.CustomEntry如果你用的不是IDEA的Artifacts而是命令行工具也可以用类似方式指定jar cfe my-app.jar com.example.CustomEntry -C out/production/classes .这里的e选项就是指定入口类。方式二用javap工具定位类如果你的程序入口不在平时熟悉的类里你想确认这个JAR包里到底哪个类有main方法可以在命令行里用jar tf查看JAR包内容然后再用javap工具反编译查看类的签名jar tf my-app.jar javap -classpath my-app.jar com.example.HiddenEntry这样可以确认某个类是否包含可运行的main方法。关于反编译JAR包的问题如果你需要查看某个类在JAR包里的实现逻辑可以使用IDEA自带的反编译功能。具体操作是把JAR包添加到项目的Libraries中然后在IDEA的Project窗口里双击打开这个类IDEA会自动反编译并展示源码。也可以使用开源的CFR、Procyon等工具。但需要注意反编译只能作为参考不是所有字节码都能完美还原成可读性高的源码。6.4 加快JAR包打包速度的小技巧最新的网络热搜词里有人专门问“如何优化加速JAR打包速度”说明这个问题确实困扰了不少人。如果你用的是Maven项目且项目比较大打包慢通常有以下几个原因依赖下载慢首次打包时要下载大量依赖这是最耗时的环节。解决方案是使用国内镜像源比如阿里云仓库镜像。在settings.xml里配置镜像源下载速度能有质的提升。重复执行测试mvn package默认会执行测试如果测试用例很多耗时很长。临时打包时可以加-DskipTests跳过测试阶段。没有使用增量编译IDEA默认会做增量编译但如果你频繁执行mvn clean每次都会全量重新编译。建议在代码变更不大、且是临时打包时不要执行clean命令直接mvn package。还有一个小技巧在IDEA的Maven面板中把打包命令Tail Log里看到的核心日志对应的问题先解决掉这样可以避免反复打包失败浪费的时间。我个人实测配置了国内镜像源后一个依赖量较大的Spring Boot项目首次打包时间能从5分钟以上降到1分多钟体验提升非常明显。7. 常见错误与排查处理7.1 “no main manifest attribute”的根源这个报错是打包场景里最常见的。我已经在前文提过一次这里再详细展开一下。no main manifest attribute, in xxx.jar这个错误翻译过来就是在xxx.jar这个文件里找不到主清单属性。主清单属性指的就是MANIFEST.MF文件里的Main-Class。产生这个报错无非以下几种原因打包时没有配置Main-Class属性。配置了Main-Class但类名包含模块名前缀格式不正确。JAR包被某些工具重新打包过MANIFEST.MF文件被覆盖了。排查方法很简单用压缩工具打开JAR包找到META-INF/MANIFEST.MF看看内容里有没有Main-Class这一行。如果没有说明打包配置没生效。解决方式也简单如果是IDEA Artifacts打包重新打开Project Structure → Artifacts确认Main Class配置无误后重新Build。如果是Maven项目按前面讲的配置maven-assembly-plugin或者检查pom.xml里是否已配置了spring-boot-maven-plugin。7.2 “ClassNotFoundException”与“NoClassDefFoundError”这两个报错本质上都是运行时找不到某个类区别在于ClassNotFoundException运行到某一行时才去加载类结果类不在classpath里。NoClassDefFoundError编译时类存在但运行时无法加载。如果执行java -jar时出现这类报错第一反应应该是依赖没有被打进JAR包里。如果你在IDEA里用的是Artifacts打包检查一下Artifacts配置页面里的Output Layout区域看依赖库是否被包含进去了。正常情况应该能看到Available Elements列表和Output Layout区域的对应关系你要把project compile output和所有library都拖进左边的输出区域。如果你是Maven项目检查pom.xml中是否有scopeprovided/scope或scopesystem/scope的依赖。这类依赖在打包时默认不会打进去。比如Servlet API就是典型的provided依赖它在Tomcat运行环境中有但如果你在本地打JAR包想独立运行就需要手动排除或调整scope。7.3 端口被占用导致的运行失败还有一种情况和打包本身无关但和运行JAR包强相关项目本身能跑但执行java -jar后报端口被占用。这个问题的种类很多比如用Spring Boot开发时默认端口8080可能被其他进程占用了。排查方式Windows下netstat -ano | findstr 8080Linux/Mac下lsof -i:8080找到占用进程后杀掉或者换端口即可。7.4 中文乱码问题如果你的程序里包含中文输出但执行JAR包时出现乱码很可能是控制台的编码格式不是UTF-8。IDEA里你看到的是正常中文是因为IDEA自己设置了UTF-8编码但命令行终端的默认编码可能是GBK或者别的什么。解决方法是在运行命令时明确指定编码java -Dfile.encodingUTF-8 -jar my-app.jar如果是Windows的cmd还可以先执行chcp 65001切换到UTF-8再运行。7.5 常见错误速查表报错信息可能原因解决方案no main manifest attributeMANIFEST.MF中缺少Main-Class重新配置Artifacts的Main Class或检查pom.xml插件配置ClassNotFoundException依赖未打进JAR包 / 类路径配置错误检查Artifacts的输出布局使用fat JAR或调整Maven依赖scopeUnsupportedClassVersionError编译JDK版本高于运行JDK版本统一编译和运行的JDK版本用java -version确认运行环境中文乱码控制台编码与程序编码不一致使用-Dfile.encodingUTF-8参数端口被占用本地有进程占用了运行端口netstat或lsof定位并清理jar包能编译但双击没反应JAR不是可执行JAR包配置Main-Class后用java -jar运行8. 进阶反编译JAR包与源码混淆8.1 别人给你JAR包怎么看它内部结构实际工作中你要么是自己打JAR包发给别人要么是接手别人打好的JAR包去维护。后者这种场景里反编译是一个很有用的技能。热词里有个词叫“反编译jar”我简单讲下常用的工具。IDEA自带反编译直接把JAR包拖进IDEA里或者通过Project Structure → Libraries → → Java添加JAR包后在Project窗口里找到对应的类双击即可看到反编译后的源码。IDEA集成的是FernFlower反编译器还原度相当高。命令行工具如果你不想开IDEA用CFR也很方便。下载CFR的JAR包后命令行执行java -jar cfr.jar xxx.jar --outputdir ./output就会在output目录下生成反编译后的.java文件。8.2 防止反编译说说源码混淆与反编译对应的另一个热词是“源码混淆”。如果你要让JAR包交付给客户又不想让别人轻易看懂核心逻辑可以考虑做代码混淆。常见的Java混淆工具包括ProGuard老牌工可以把类名、方法名、字段名改成无意义字符删除未使用的代码甚至做代码优化。Allatori商业级的混淆工具混淆强度很高。yGuard开源但活跃度一般。需要说明的是混淆只能提高逆向的门槛不能完全防止反编译。因为JVM要能加载类字节码里必然保留了可执行的信息唯一能做的是让这些信息变得难以理解。如果你的项目对安全性要求很高我建议在架构层面做防护比如把核心算法放到服务端客户端只保留调用逻辑而不是指望混淆工具能一劳永逸。9. 不同场景下的打包方案选择9.1 依赖方的通用JAR包与可执行JAR包之前的标题和热词里涉及到“jar包指定函数入口”以及“jar包反编译”这样的需求说明很多人已经在处理别人交付的JAR包而不只是自己闷头写代码了。我先梳理一下什么场景下应该打什么类型的包交付场景推荐打包类型说明给其他项目作为依赖库引用普通JAR包不需要配置Main-Class打上类的路径和资源文件即可给运维部署独立的服务可执行JAR包fat JAR需要配置Main-Class并把运行所需依赖打进包中给测试做接口联调可执行JAR包保证对方拿到后能直接java -jar启动Spring Boot微服务Spring Boot fat JAR使用spring-boot-maven-plugin打包自带内嵌容器9.2 每隔一段时间就要手动打包考虑用脚本如果你隔三差五就要打一次JAR包那手动点IDEA确实效率太低了。我建议你写一个简单的脚本一键完成编译、打包、拷贝到指定目录的操作。Windows下的bat脚本示例echo off echo 开始打包 call mvn clean package -DskipTests copy target\my-app-1.0.0.jar D:\deploy\ echo 打包完成 pauseLinux/Mac下的shell脚本示例#!/bin/bash echo 开始打包 mvn clean package -DskipTests cp target/my-app-1.0.0.jar /opt/deploy/ echo 打包完成这样每次构建只需执行一个脚本不用再打开IDEA的Maven面板等待构建结束。9.3 一个特殊场景本地打好的包别人机器上运行报版本错误有一种问题经常在前后端联调时出现你在IDEA里用JDK 17编译打包对方机器上装的是JDK 8结果运行时报UnsupportedClassVersionError。这个错误的含义是class文件编译所用的Java版本高于当前JVM支持的版本。排查方式先确认对方机器的Java版本java -version再看自己打包时用的JDK版本。如果编译版本高于运行版本要么让对方升级JDK要么你在Maven中指定编译版本为较低版本比如properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties这种方式在混合环境部署时特别实用。10. 常见问题排查实录10.1 双击JAR包无法启动很多初学者辛辛苦苦把JAR包打出来然后双击发现窗口一闪而过或者直接没反应。首先要明确JAR包并不是双击就能运行的程序。只有在系统里正确安装了Java运行时并且将.jar文件关联到了javaw.exe双击才可能有效。而且即使双击有效控制台的输出也看不到程序出错的话你完全不知道发生了什么。所以我强烈建议不要用双击方式运行JAR包一律用命令行启动。java -jar your-app.jar这样日志能直接打印在终端里出错了也能看到栈信息排查起来很容易。10.2 打包后文件缺失比如配置文件、图片、XML等打包后发现资源文件没进JAR包这也非常常见。在IDEA的Artifacts配置页面里左侧Available Elements区域会把项目的所有元素列出来包括编译输出、资源目录、依赖库等。你需要把src/main/resources或对应模块的资源目录也拖到右侧的Output Layout里。如果是Maven项目默认情况下会打包resources目录下的所有文件但如果某些文件被过滤规则排除了也会导致资源缺失。排查方法就是打开最终JAR包看resources或相对路径下是否有对应的文件。如果使用maven-assembly-plugin可以加一个显式的资源声明resources resource directorysrc/main/resources/directory /resource /resources10.3 用Spring Boot打的JAR包解压后结构很奇怪如果你用spring-boot-maven-plugin打包解压后会发现里面有一个BOOT-INF目录项目的class文件在BOOT-INF/classes下依赖在BOOT-INF/lib下而且传统的META-INF/MANIFEST.MF里的Main-Class指向的是org.springframework.boot.loader.JarLauncher而不是你自己的业务类。这不是出错而是Spring Boot自定义的加载方式。Spring Boot的启动器会通过自定义的类加载器去加载BOOT-INF/classes和BOOT-INF/lib下的类所以即便你的业务类不直接出现在Main-Class里也能被正确加载。如果你需要把这个Spring Boot JAR包当作普通依赖引入其他项目是不行的。需要额外生成一个只包含自己类的普通JAR包或者用mvn package时配合classifier配置来区分。Spring Boot的JAR包本身就是为独立运行设计的别拿它当普通依赖用。11. 写在最后的几点心得如果你是从头读到这里的可以感受到用IDEA打JAR包这件事本身并不复杂真正的难点在于搞清楚背后的运行机制。我前面讲了这么多总结起来其实就三句话第一搞清楚JAR包的类型。普通JAR包和可执行JAR包是两个不同的东西你要在动手之前想清楚打哪种。给依赖方用打普通JAR包要独立运行打可执行JAR包。第二学会阅读报错信息。no main manifest attribute告诉你是入口没配好ClassNotFoundException告诉你是依赖没打进去或classpath不对UnsupportedClassVersionError告诉你是JDK版本不一致。报错信息是排查问题的第一线索别一上来就怀疑工具。第三把重复的操作自动化。如果打包是你日常频繁要做的事用Maven的mvn package加上脚本远比每次打开IDEA手动点菜单高效得多。我个人在实际操作中还有一个习惯每次打包完成后我都习惯用解压工具打开JAR包快速检查一遍确认MANIFEST.MF配置正确、关键类在里面、依赖没有缺失。这个习惯帮我规避了很多低级问题每次都是花半分钟的时间省掉后续的沟通和返工成本。最后分享一个小技巧如果你是做Java服务端开发的建议养成每次构建都带上版本号的习惯比如my-app-20250112.jar或者用Maven的版本号自动加上日期后缀。这样部署到服务器上后你一眼就能知道跑的是哪个时间点构建的包排查线上问题时能节省大量时间。好这篇关于IDEA打包JAR的文章就到这里。如果你在实际操作中遇到了其他问题建议先用压缩工具把JAR包打开看看对照这篇内容逐一排查大概率能找到原因。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。