1. 概述
每个可执行的 Java 类都必须包含一个 main()
方法——这是整个应用的入口点,这点大家都知道 ✅。
但当我们想通过 java -jar example.jar
直接运行一个 JAR 包时,却经常遇到这个经典报错:
no main manifest attribute, in example.jar
这个错误的意思很明确:JAR 包的 MANIFEST.MF 文件中缺少 Main-Class
声明,导致 JVM 找不到入口类 ❌。
本文将带你从零构建一个可执行 JAR,深入理解 Main-Class
的作用,并总结常见“踩坑”点。最后还会覆盖 Maven、Gradle、Ant 和主流 IDE 的配置方式,确保你以后打包不再翻车。
2. 没有 Main Manifest 属性时的执行尝试
我们先写一个最简单的入口类:
public class AppExample {
public static void main(String[] args){
System.out.println("AppExample executed!");
}
}
编译并打包成 JAR(不带自定义 manifest):
javac -d . AppExample.java
jar cvf example.jar com/baeldung/manifest/AppExample.class
此时 JAR 内会包含一个默认的 MANIFEST.MF
,但里面没有 Main-Class
。
执行:
java -jar example.jar
结果报错:
no main manifest attribute, in example.jar
2.1 手动指定主类绕过问题
虽然不能用 -jar
,但我们可以通过 -cp
手动指定类路径和主类来运行:
java -cp example.jar com/baeldung/manifest/AppExample
或等价写法:
java -classpath example.jar com/baeldung/manifest/AppExample
✅ 输出正常:
AppExample executed!
⚠️ 注意:这种方式需要用户知道主类全名,不适合分发。真正的“可执行 JAR”应该做到开箱即用,-jar
直接运行。
3. 正确添加 Main Manifest 属性
要让 JAR 支持 java -jar
,必须在 MANIFEST.MF
中声明 Main-Class
。
创建文件 MANIFEST.MF
,内容如下:
Main-Class: com.baeldung.manifest.AppExample
⚠️ 注意:
- 类名必须是全限定名(包含 package)
- 行尾必须有换行符(下文会强调)
使用 -m
参数将自定义 manifest 打包进 JAR:
jar cvmf MANIFEST.MF example.jar com/baeldung/manifest/AppExample.class
再次执行:
java -jar example.jar
✅ 成功输出:
AppExample executed!
4. 构建可执行 JAR 的常见踩坑点
即使加了 Main-Class
,仍可能报错。以下是几个经典翻车场景 ⚠️。
4.1 Main-Class
类名拼写错误
最常见问题:类名写错或漏了包路径。
❌ 错误示例:
Main-Class: AppExample
✅ 正确应为:
Main-Class: com.baeldung.manifest.AppExample
Java 会严格按照这个全限定名去加载类,差一个字母都找不到 ❌。
4.2 manifest 文件末尾缺少空行
这是很多人忽略的细节:JAR 的 manifest 文件每一项必须以换行结束,且文件末尾必须有一个空行。
❌ 错误写法(无结尾换行):
Main-Class: com.baeldung.manifest.AppExample
✅ 正确写法(末尾有换行):
Main-Class: com.baeldung.manifest.AppExample
[此处有一个空行]
如果没有这个空行,JVM 可能无法正确解析 manifest,导致 Main-Class
被忽略。
4.3 manifest 文件位置或打包方式错误
使用 jar
命令时,如果没用 -m
指定自定义 manifest,就会使用默认的,而默认的没有 Main-Class
。
另外,手动解压 JAR 后检查,MANIFEST.MF
必须位于:
META-INF/MANIFEST.MF
如果路径不对,或者被打包到了其他目录,JVM 也找不到。
5. 使用构建工具自动添加 Main-Class
手动维护 MANIFEST.MF
太原始了。现代项目推荐用构建工具自动生成,更可靠 ✅。
5.1 Maven 配置
在 pom.xml
中配置 maven-jar-plugin
:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<archive>
<manifest>
<mainClass>com.baeldung.manifest.AppExample</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
执行:
mvn package
生成的 JAR 位于 target/
目录,manifest 已自动包含 Main-Class
。
5.2 Gradle 配置
在 build.gradle
中添加:
jar {
manifest {
attributes(
'Main-Class': 'com.baeldung.manifest.AppExample'
)
}
}
执行:
gradle build
可执行 JAR 生成在 build/libs/
。
💡 提示:如果你用
application
插件,可以直接用mainClassName
或mainClass
属性,更简单。
5.3 Ant 配置
在 build.xml
中:
<target name="jar" depends="compile">
<jar destfile="dist/example.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="com.baeldung.manifest.AppExample"/>
</manifest>
</jar>
</target>
Ant 会自动在 META-INF/
下生成正确的 MANIFEST.MF
。
5.4 IDE 配置(IntelliJ & Eclipse)
IntelliJ IDEA
File > Project Structure > Artifacts
+ > JAR > From modules with dependencies
- 选择模块和主类
- 勾选 “Extract to the target JAR”
Build > Build Artifacts
✅ 生成的 JAR 自带正确 manifest。
Eclipse
- 右键项目 →
Export
- 选择
Runnable JAR file
- 选择运行配置(即主类)
- 设置输出路径和库依赖处理方式
- 点击
Finish
Eclipse 会自动创建 MANIFEST.MF
并设置 Main-Class
,简单粗暴但有效。
6. 总结
Main-Class
是可执行 JAR 的核心,缺了它java -jar
就会报no main manifest attribute
❌- 手动打包时务必:
- ✅ 使用全限定类名
- ✅ manifest 文件末尾加空行
- ✅ 用
jar cvmf
正确打包
- 推荐使用构建工具(Maven/Gradle)或 IDE 自动生成 manifest,避免手写出错 ✅
- 遇到问题先检查:
- JAR 包内
META-INF/MANIFEST.MF
是否存在 Main-Class
是否拼写正确- 文件末尾是否有换行
- JAR 包内
掌握了这些,以后打包 JAR 再也不会被这个低级错误卡住。