Gradle Shadow Plugin打包Jar在Docker容器运行报错:无主清单属性
问题分析与解决方案
你的问题核心出在Docker镜像构建时复制了错误的Jar文件,或者Dockerfile中Jar文件名不匹配,导致容器内运行的Jar并非你本地测试的Shadow Fat Jar。
可能的原因
Gradle同时生成了普通Jar和Shadow Fat Jar
默认情况下,Gradle的jar任务会生成一个不含依赖的普通Jar,而shadowJar任务生成Fat Jar,两者共存于build/libs目录。当你用COPY build/libs/*jar fat_jar_name-all.jar时,Docker可能会复制到普通Jar(按文件名排序后被选中),而普通Jar的MANIFEST可能缺失主类属性。Dockerfile中文件名逻辑冲突
你将复制的Jar重命名为fat_jar_name-all.jar,但ENTRYPOINT中执行的是java -jar fat_jar_name.jar——虽然你的错误信息指向fat_jar_name-all.jar,但说明实际复制到容器的Jar并非你本地测试的Shadow Fat Jar。
解决方案
1. 固定Shadow Jar的文件名(Gradle配置)
修改shadowJar任务,指定固定的输出文件名,避免版本号干扰,同时可禁用普通Jar任务减少混淆:
tasks { "build" { dependsOn(shadowJar) } // 禁用普通jar任务,避免生成多余Jar jar { enabled = false } shadowJar { mergeServiceFiles { var path = "META-INF/" } manifest.inheritFrom(jar.get().manifest) manifest.attributes["Main-Class"] = "some.main.class.Main" manifest.attributes["Implementation-Version"] = version // 固定输出文件名 archiveFileName = "fat_jar_name-all.jar" } }
2. 修正Dockerfile,明确复制Shadow Jar
修改Dockerfile,指定精确的Jar文件名,避免模糊匹配导致的错误:
FROM eclipse-temurin:17 # 明确指定Shadow生成的Jar ARG JAR_FILE=build/libs/fat_jar_name-all.jar COPY ${JAR_FILE} app.jar # 使用数组形式的ENTRYPOINT(更规范,避免命令解析问题) ENTRYPOINT ["java", "-jar", "/app.jar"]
3. 构建前清理旧产物
构建Docker镜像前,先执行Gradle清理命令,确保build/libs目录只有最新的Shadow Jar:
gradle clean build
4. 验证容器内的Jar(可选)
如果仍有问题,可进入容器验证Jar内容:
# 启动交互容器 docker run -it --rm image_name bash # 查看Jar内的MANIFEST文件 unzip -p app.jar META-INF/MANIFEST.MF
确认输出包含正确的Main-Class属性。
内容的提问来源于stack exchange,提问作者buzoherbert
相关产品推荐
相关产品推荐

