
简介这份PDF资料聚焦IDEA环境下打包可执行jar文件时常见的“找不到或无法加载主类 main”报错面向使用IntelliJ IDEA进行Java开发、需要将项目打包为可运行jar的初中级开发者。内容围绕问题成因与两类解决路径展开一是通过Maven项目在pom.xml中配置maven-jar-plugin插件正确填写mainClass全限定名并开启addClasspath使依赖自动进入classpath二是借助IDEA的Build Artifacts功能直接构建可运行jar并补充了Windows下CLASSPATH环境变量的排查与处理思路。资源包共1个PDF文件约258KB篇幅精炼、便于随查随用。目前已有20875人学习下载适合在打包环节反复踩坑、希望快速定位主类配置与环境变量问题的读者参考可帮助减少试错成本提升jar打包与运行的成功率。1. 从一次打包翻车说起IDEA 里那个让人抓狂的 main 类上周帮同事看一个安全小工具代码在 IDEA 里跑得好好的一打成 jar 丢到测试机上就报找不到或无法加载主类 main。他反复确认了public static void main(String[] args)没写错甚至把 JDK 从 8 换到 17 又换回来问题依旧。这个报错在 IDEA 打包 jar 的场景里出现频率极高尤其是用 Maven 构建、又没配maven-jar-plugin的时候。它本质上不是代码写错了而是 jar 包里的META-INF/MANIFEST.MF没告诉 JVM 该从哪个类开始执行。这篇文章就围绕 IDEA 打包 jar 时主类 main 找不到的问题把 Maven 插件配置、IDEA Artifacts 构建、CLASSPATH 环境变量这三条路都走一遍顺带把addClasspath、mainClass全限定名、java -jar执行链路这些参数讲透。适合正在用 IDEA 做 Java 小工具、需要交付可执行 jar 的开发者也适合被CLASSPATH玄学坑过的老手回顾一遍。2. Maven 方式打包maven-jar-plugin 的 mainClass 到底填什么2.1 为什么默认打出来的 jar 跑不起来Maven 默认的maven-jar-plugin只会把编译后的 class 文件按包结构塞进 jar生成的MANIFEST.MF里通常只有Manifest-Version和Created-By两行没有Main-Class属性。JVM 执行java -jar xxx.jar时会先读 manifest找不到Main-Class就直接抛找不到或无法加载主类 main。注意这里报的是main而不是你的类名因为 JVM 在缺省情况下把入口名当成了main这个类去 classpath 里找自然找不到。所以解决思路很明确让 manifest 里出现正确的Main-Class并且把依赖的 classpath 也写进去。2.2 配置 maven-jar-plugin 的完整 pom 片段在pom.xml的build里加插件这是最稳的做法。下面这段可以直接抄注意mainClass的值build plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId version3.0.2/version configuration archive manifest !-- 把依赖 jar 的路径写进 manifest 的 Class-Path -- addClasspathtrue/addClasspath !-- 主类全限定名从 /src/main/java 下的包路径开始写 -- mainClassMain/mainClass /manifest /archive /configuration /plugin /plugins /build逻辑说明archive控制 manifest 生成manifest里的两个子标签分别对应Class-Path和Main-Class。addClasspathtrue会让插件把项目依赖的 jar 以相对路径形式写进Class-Path这样java -jar时 JVM 能顺着找到第三方库。参数说明mainClass填的是全限定名如果你的主类在com.example.tool包下、类名是Main就必须写com.example.tool.Main只写Main只在默认包无 package 声明下才有效。原文示例里写Main是因为它的类就在/src/main/java根下没有包声明这点新手最容易照抄出错。2.3 打包与验证命令配好之后执行# 清理后重新打包-DskipTests 跳过测试加快速度 mvn clean package -DskipTests # 查看生成的 manifest确认 Main-Class 和 Class-Path 是否正确 unzip -p target/code-1.0-SNAPSHOT.jar META-INF/MANIFEST.MF # 运行 jar java -jar target/code-1.0-SNAPSHOT.jar逻辑说明mvn clean package会触发 jar 插件重新生成 manifest如果之前打过包不 clean 可能残留旧 manifest。unzip -p直接把 manifest 打到终端重点看Main-Class:后面是不是你填的全限定名Class-Path:后面是不是有一串依赖 jar 的相对路径。参数说明-DskipTests只是跳过测试执行不影响编译如果你的项目有多个模块要在包含主类的那个模块目录下执行 package。运行阶段如果还报找不到主类先看 manifest再看 jar 里 class 文件的包路径是否和mainClass一致九成问题出在这两处对不上。3. IDEA Artifacts 方式不写 pom 也能打出可执行 jar3.1 Artifacts 的构建逻辑与适用场景不是所有项目都用 Maven有些小工具就是纯 Java 项目或者你临时改了个类不想动 pom。IDEA 自带的 Artifacts 功能可以绕过 Maven直接按你指定的输出布局打 jar。它的原理是你告诉 IDEA 主类是谁、依赖库放哪、输出目录在哪IDEA 在Build Artifacts时生成 manifest 并组装 jar。适合单模块、依赖不多、快速交付的场景。缺点是配置存在.idea目录里换台机器或换个人就得重新配团队协作不如 Maven 插件稳定。3.2 从 Project Structure 到 Build Artifacts 的完整步骤第一步打开File Project Structure Artifacts点选JAR From modules with dependencies。第二步在Main Class那一栏点文件夹图标选中你的主类IDEA 会自动填全限定名。第三步JAR files from libraries选extract to the target JAR这样依赖会被解压合并进同一个 jar避免运行时找不到依赖如果依赖多、想保持 jar 体积小就选copy to the output directory and link via manifest依赖会放在 jar 同级目录。第四步确认Output directory和Output LayoutBuild Build Artifacts Build或Rebuild。# 构建完成后产物一般在 out/artifacts/ 下 java -jar out/artifacts/code_jar/code.jar逻辑说明extract to the target JAR会把依赖的 class 直接打进你的 jarmanifest 里不需要Class-Path适合依赖少的情况copy to the output directory会生成一个 lib 目录manifest 里写相对路径适合依赖多、想复用依赖的场景。参数说明Main Class必须选到有main方法的那个类IDEA 不会帮你校验方法签名选错了照样报找不到主类。构建后如果报错先检查Output Layout里主类的 class 文件是否在 jar 根路径对应的包目录下。3.3 两种打包方式的对比与选型对比项Maven maven-jar-pluginIDEA Artifacts配置位置pom.xml随代码走.idea 目录本地生效依赖处理addClasspath 写 manifest可选合并或外链团队协作一致性好每人需重新配适用场景正式项目、CI 构建临时工具、快速验证主类填写全限定名手写图形选择自动填选型建议要进 CI、要交付给别人的一律用 Maven 插件只是本地跑个一次性工具Artifacts 更快。两者不冲突可以同时存在但注意别把两种方式打出来的 jar 混用manifest 格式不一样。4. 避坑与排查CLASSPATH 和那些让人怀疑人生的报错4.1 现象删掉 CLASSPATH 变量后突然就好了原因Windows 上如果CLASSPATH环境变量被设成了固定路径JVM 会优先按它去找类而不是按java -jar传入的 jar。你 jar 里明明有主类但 JVM 去CLASSPATH指的目录里找找不到就报找不到或无法加载主类 main。解决直接删除CLASSPATH环境变量让 JVM 用默认行为当前目录加 jar 自身。如果业务要求保留就改成.;%JAVA_HOME%\lib前面那个点代表当前目录分号隔开。改完要重开终端环境变量不会热生效。4.2 现象manifest 里 Main-Class 写了但还报错原因Main-Class的值和 jar 内 class 的实际包路径不一致。比如你写了com.example.Main但编译出来的 class 在com/example/tool/Main.class。解决用unzip -l xxx.jar | grep Main看 class 的真实路径把路径里的/换成.、去掉.class就是全限定名。另一个常见原因是主类没有public static void main(String[] args)或者方法写成了main(String args)少了方括号JVM 认不出来。4.3 现象依赖库报 ClassNotFoundException原因addClasspathtrue写进 manifest 的是相对路径java -jar时工作目录不对相对路径就失效了。解决要么在 jar 所在目录执行命令要么改用 Artifacts 的extract to the target JAR把依赖合并进去。用 Maven 的话也可以上maven-shade-plugin打 fat jar但那是另一个插件的事本文不展开。4.4 现象IDEA 里运行正常命令行 java -jar 就挂原因IDEA 运行时会自动把模块依赖、输出目录都加进 classpath命令行没有这套上下文。解决以命令行结果为准去配 manifest别拿 IDEA 的运行结果当验收标准。打包后一定用java -jar实跑一遍这一步不能省。4.5 现象改了主类名重新打包还是旧入口原因Maven 增量打包没清理旧 manifest或者 IDEA 的 Artifacts 没点 Rebuild 只点了 Build。解决Maven 用mvn clean packageArtifacts 用Rebuild。改主类名属于结构性变更必须全量重建。5. 进阶技巧用 maven-shade-plugin 打 fat jar 并验证入口Maven 的maven-jar-plugin只负责写 manifest依赖还是外链的交付时得连 lib 目录一起给。想打成一个自带所有依赖的 fat jar常见做法是换maven-shade-plugin。它会把依赖的 class 解压合并进你的 jar同时用ManifestResourceTransformer指定主类。配置如下plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-shade-plugin/artifactId version3.4.1/version executions execution phasepackage/phase goalsgoalshade/goal/goals configuration transformers transformer implementationorg.apache.maven.plugins.shade.resource.ManifestResourceTransformer !-- 全限定名和 jar 插件规则一致 -- mainClasscom.example.tool.Main/mainClass /transformer /transformers /configuration /execution /executions /plugin逻辑说明phasepackage表示在 package 阶段执行 shadeManifestResourceTransformer负责往合并后的 manifest 写Main-Class。参数说明mainClass同样填全限定名如果项目里有多个主类只能指定一个作为入口。打完包后验证# 确认 fat jar 里 manifest 的 Main-Class unzip -p target/code-1.0-SNAPSHOT.jar META-INF/MANIFEST.MF | grep Main-Class # 确认依赖 class 已被合并进来比如 requests 库 unzip -l target/code-1.0-SNAPSHOT.jar | grep net/dongliu # 实跑 java -jar target/code-1.0-SNAPSHOT.jar逻辑说明第一条确认入口第二条确认依赖真的在 jar 里而不是外链第三条是最终验收。参数说明grep的路径按你实际依赖的包名调整原文示例依赖的是net.dongliu:requests所以查net/dongliu。如果第二条查不到说明 shade 没生效检查插件是否绑到了 package 阶段、有没有被其他插件覆盖。还有一个容易被忽略的点maven-jar-plugin和maven-shade-plugin同时存在时shade 会基于 jar 插件的产物再加工manifest 可能被覆盖。我一般只留 shade把 jar 插件的mainClass配置去掉避免两个插件打架。另外JDK 9 以后模块化项目打 fat jar 可能遇到module-info.class冲突shade 3.4.1 支持filters排除但那是模块化场景的事普通项目碰不到。从那以后我每次打完 jar都强制走一遍「看 manifest → 查 class 路径 → 命令行实跑」这三步再也没被找不到或无法加载主类 main坑过。希望帮到你。本文还有配套的精品资源点击获取