当你尝试使用 java -jar app.jar 命令运行一个 JAR 文件时,如果看到错误信息 “no main manifest attribute, in app.jar”,这意味着该 JAR 文件的清单文件(MANIFEST.MF)中缺少了 Main-Class 属性。JVM 无法确定程序的入口点,因此无法启动应用程序。
本文将全面解析此问题的原因,并提供针对不同构建工具和开发环境的详细解决方案。
每个 JAR 文件都包含一个特殊的清单文件:META-INF/MANIFEST.MF。这个文件包含了关于 JAR 包的元数据信息。
可执行 JAR 文件的 MANIFEST.MF 应该包含: Manifest-Version: 1.0 Main-Class: com.example.DemoApplication
普通 JAR 文件的 MANIFEST.MF(缺少 Main-Class): Manifest-Version: 1.0
当使用 java -jar 命令时,JVM 会: 1. 解压 JAR 文件 2. 查找 META-INF/MANIFEST.MF 文件 3. 在清单文件中寻找 Main-Class 属性 4. 如果找不到,就会抛出 "no main manifest attribute" 错误
- 构建配置缺失:Maven/Gradle 配置中没有正确指定主类 - 使用了错误的打包方式:直接使用 jar 命令打包,而不是使用构建工具的可执行 JAR 功能 - Spring Boot 项目配置问题:未正确配置 spring-boot-maven-plugin - IDE 导出设置错误:在 IDE 中导出 JAR 时未选择 "Runnable JAR" 选项
对于 Spring Boot 项目,必须使用 spring-boot-maven-plugin 来生成可执行的 JAR 文件。
正确的 pom.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo-application</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 显式指定主类(可选,Spring Boot 通常能自动检测) -->
<mainClass>com.example.DemoApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project><build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.DemoApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>关键要点: - 确保 设置为 jar(不是 pom) - 必须包含 spring-boot-maven-plugin - 不要设置 true 或类似的跳过配置
对于非 Spring Boot 的普通 Maven 项目,需要配置 maven-jar-plugin:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.DemoApplication</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>确保使用正确的构建命令:
清理并重新构建 mvn clean package
或者直接构建可执行 JAR mvn clean install
构建完成后,检查生成的 JAR 文件:
查看 MANIFEST.MF 内容 jar -tf target/app.jar | grep MANIFEST.MF jar -xf target/app.jar META-INF/MANIFEST.MF cat META-INF/MANIFEST.MF
build.gradle 配置:
plugins { id 'org.springframework.boot' version '2.7.0' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' }
group = 'com.example' version = '1.0.0' sourceCompatibility = '11'
configurations { compileOnly { extendsFrom annotationProcessor } }
repositories { mavenCentral() }
dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
// 显式指定主类(可选) springBoot { mainClass = 'com.example.DemoApplication' }
tasks.named('test') { useJUnitPlatform() }
3.2 普通 Gradle 项目
jar { manifest { attributes( 'Main-Class': 'com.example.DemoApplication' ) } }
构建项目 ./gradlew clean build
对于 Spring Boot 项目,生成的可执行 JAR 在 build/libs/ 目录下 java -jar build/libs/app.jar
Spring Boot 项目: 1. 确保使用 Maven/Gradle 构建,而不是 IDEA 的内置打包功能 2. 如果必须使用 IDEA 导出: - File → Project Structure → Artifacts - 添加 JAR → from modules with dependencies - 选择主类 - 勾选 "Include in project build"
普通 Java 项目: 1. File → Project Structure → Artifacts 2. 点击 + → JAR → from modules with dependencies 3. 选择包含 main 方法的模块 4. 指定主类 5. 选择 "Extract to the target JAR" 选项
1. 右键项目 → Export 2. 选择 Java → Runnable JAR file 3. 选择启动配置(Launch configuration) 4. 指定导出位置 5. 选择库处理方式(推荐 "Package required libraries into generated JAR")
如果你需要手动创建可执行 JAR 文件,可以按照以下步骤:
创建一个名为 MANIFEST.MF 的文件,内容如下:
Manifest-Version: 1.0 Main-Class: com.example.DemoApplication
注意: 文件末尾必须有一个空行!
编译源代码 javac -d out src/com/example/DemoApplication.java
创建可执行 JAR jar cfm app.jar MANIFEST.MF -C out .
运行 java -jar app.jar
在 Docker 容器中遇到此问题通常是由于构建过程不正确导致的。
对于 Spring Boot 应用:
FROM openjdk:11-jre-slim
设置工作目录 WORKDIR /app
复制 JAR 文件 COPY target/app.jar app.jar
暴露端口(如果需要) EXPOSE 8080
运行应用 ENTRYPOINT ["java", "-jar", "app.jar"]
构建和运行命令:
先在本地正确构建 JAR mvn clean package
构建 Docker 镜像 docker build -t my-app .
运行容器 docker run --rm my-app
构建阶段 FROM maven:3.8.4-openjdk-11 AS build WORKDIR /app COPY pom.xml . COPY src ./src RUN mvn clean package -DskipTests
运行阶段 FROM openjdk:11-jre-slim WORKDIR /app COPY --from=build /app/target/app.jar app.jar ENTRYPOINT ["java", "-jar", "app.jar"]
列出 JAR 文件内容 jar -tf app.jar
提取并查看 MANIFEST.MF jar -xf app.jar META-INF/MANIFEST.MF cat META-INF/MANIFEST.MF
或者直接查看 unzip -p app.jar META-INF/MANIFEST.MF
检查主类是否在 JAR 中 jar -tf app.jar | grep DemoApplication.class
如果暂时无法修复 JAR 文件,可以使用以下方式运行:
不使用 -jar 参数,而是指定 classpath java -cp app.jar com.example.DemoApplication
确保构建过程中没有警告或错误:
Maven 构建时的正常输出应该包含 repackage 步骤 [INFO] --- spring-boot-maven-plugin:2.7.0:repackage (repackage) @ demo-application --- [INFO] Replacing main artifact with repackaged archive
如果看到类似 [INFO] Skipping repackaging 的消息,说明配置有问题。
在多模块项目中,确保在包含主类的模块中配置了 spring-boot-maven-plugin
<!-- 在子模块的 pom.xml 中 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>如果主类名称不标准,需要显式指定:
com.example.custom.CustomStartup
// Gradle springBoot { mainClass = 'com.example.custom.CustomStartup' }
有时依赖冲突会导致插件无法正常工作。可以尝试:
清理本地 Maven 仓库中的相关依赖 rm -rf ~/.m2/repository/org/springframework/boot/ mvn clean package
- 使用 Spring Initializr 创建 Spring Boot 项目,确保基础配置正确 - 选择合适的构建工具(Maven 或 Gradle)
- 定期验证构建过程:mvn clean package 或 ./gradlew build - 在本地测试 JAR 文件:java -jar target/app.jar - 使用版本控制系统跟踪构建配置文件
- 在 CI/CD 流程中包含 JAR 文件验证步骤 - 使用容器化部署确保环境一致性 - 记录和文档化构建和部署过程
- 启用详细日志:mvn clean package -X - 比较工作正常的 JAR 和有问题的 JAR 的 MANIFEST.MF 文件 - 使用 jar -tvf app.jar 查看详细的 JAR 内容列表
“no main manifest attribute, in app.jar” 错误的根本原因是 JAR 文件缺少必要的 Main-Class 清单属性。解决这个问题的关键在于:
1. 正确配置构建工具:确保 Maven 或 Gradle 配置中包含了生成可执行 JAR 的必要插件和配置 2. 使用正确的构建命令:使用 mvn package 或 ./gradlew build 而不是简单的编译命令 3. 验证构建结果:在部署前检查生成的 JAR 文件是否包含正确的 MANIFEST.MF 4. 遵循最佳实践:使用标准的项目结构和构建配置
通过本文提供的系统性解决方案,你应该能够快速诊断和解决这个常见的 Java 部署问题。记住,预防胜于治疗——在开发阶段就建立正确的构建和测试流程,可以避免在生产环境中遇到此类问题。