必须显式配置manifest的Main-Class属性,否则java -jar会报“no main manifest attribute”错误;Gradle默认jar任务不写入该属性,需在jar { manifest { attributes 'Main-Class': 'com.example.Main' } }中手动指定全限定类名。

jar任务里必须显式配置manifest属性
Gradle默认的jar任务不会自动写入Main-Class,哪怕你用了application插件——它只影响distZip或installDist这类分发任务,跟jar输出无关。不手动配置,打包出来的JAR就只有Manifest-Version: 1.0,没有Main-Class,运行java -jar app.jar必然报no main manifest attribute。
正确做法是在build.gradle中直接修改jar任务:
- 确保
plugins { id 'java' }已启用(application插件非必需) - 用
jar { manifest { attributes ... } }块注入主类 -
attributes里的键名必须是'Main-Class'(大小写敏感),值必须是全限定类名,比如'com.example.Main' - 如果项目依赖未打包进JAR,还需额外加
from { configurations.runtimeClasspath }或改用shadow插件
jar {
manifest {
attributes 'Main-Class': 'com.example.Main'
}
}
application插件的mainClassName不生效于jar任务
很多人以为只要加了application插件并设了mainClassName = 'com.example.Main',jar任务就会自动带上Main-Class。事实不是这样:mainClassName只被run、startScripts等任务使用,对jar任务完全无影响。
如果你同时用了application插件,又想复用它的配置,可以手动读取:
jar {
manifest {
attributes 'Main-Class': project.findProperty('application.mainClass') ?: 'com.example.Main'
}
}
但更稳妥的方式还是明确写死或通过-P参数传入,避免隐式依赖。
Spring Boot项目不能用普通jar任务配Main-Class
Spring Boot项目必须用spring-boot-gradle-plugin,否则即使你在jar任务里写了Main-Class,打出来的也不是可执行胖包——缺少启动类加载器、嵌入式容器和依赖解压逻辑。
正确配置是启用插件并设置mainClass(注意不是mainClassName):
plugins {
id 'org.springframework.boot' version '3.3.5''
}
application {
mainClass = 'com.example.DemoApplication'
}
然后运行./gradlew bootJar,生成的是build/libs/*.jar,其META-INF/MANIFEST.MF里会包含Start-Class和Spring-Boot-Classes等专用属性,而不是普通Main-Class。
检查MANIFEST.MF是否真的写进去了
最容易忽略的一步:你以为配好了,其实没生效。验证方法很简单:
- 执行
./gradlew jar(或bootJar) - 用
jar -tf build/libs/app.jar | grep MANIFEST确认文件存在 - 用
jar -xf build/libs/app.jar META-INF/MANIFEST.MF && cat META-INF/MANIFEST.MF查看内容
注意:Gradle 7.0+ 默认使用zip64和时间戳归档,可能导致jar -tf输出顺序混乱,务必用jar -xf提取后看原始内容。如果看到Main-Class: com.example.Main且末尾有空行,才算真正成功。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











