Docker部署Spring Boot应用遇NoClassDefFoundError问题求助
问题描述
尝试通过docker-compose搭配Dockerfile构建并运行基于apka:apka镜像的Spring Boot容器,但容器无法启动,抛出如下异常:
21:42 Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication at ZadanieRekrutacyjne.ZadanieRekrutacyjne.ZadanieRekrutacyjneApplication.main(ZadanieRekrutacyjneApplication.java:16) Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) 1 more
曾尝试调整Spring Boot版本解决依赖兼容问题,但无效,还手动在资源目录添加了MANIFEST-INF目录及MANIFEST.FM文件。以下是相关配置与代码:
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 https://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.6.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>ZadanieRekrutacyjne</groupId> <artifactId>ZadanieRekrutacyjne</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ZadanieRekrutacyjne</name> <description>Plants</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.26</version> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>3.0.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>3.0.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.0.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <version>3.0.4</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>4.0.1.RELEASE</version> <executions> <execution> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </execution> </executions> </plugin> </plugins> </pluginManagement> </build> </project>
Dockerfile
FROM openjdk:17 ADD target/ZadanieRekrutacyjne-0.0.1-SNAPSHOT.jar ZadanieRekrutacyjne-0.0.1-SNAPSHOT.jar CMD ["java", "-jar", "/ZadanieRekrutacyjne-0.0.1-SNAPSHOT.jar"]
docker-compose.yml
version: '3.8' services: sql-test: container_name: sql-test image: mysql:5.7 environment: MYSQL_DATABASE: zadanierekrutacyjne MYSQL_USER: recruit MYSQL_PASSWORD: recruit MYSQL_ROOT_PASSWORD: Krzysiek123qweasd,./ volumes: - "./sql-test:/data/mysqldb" expose: - "3306" ports: - "3307:3306" restart: always apka: container_name: apka image: apka:apka build: . ports: - "8080:8080" environment: - spring.profiles.active= depends_on: - sql-test
主类代码
package ZadanieRekrutacyjne.ZadanieRekrutacyjne; import ZadanieRekrutacyjne.ZadanieRekrutacyjne.Security.Security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Import; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EntityScan("ZadanieRekrutacyjne.ZadanieRekrutacyjne.Entity") @EnableJpaRepositories("ZadanieRekrutacyjne.ZadanieRekrutacyjne.Repositories") @Import(Security.class) public class ZadanieRekrutacyjneApplication { public static void main(String[] args) { SpringApplication.run(ZadanieRekrutacyjneApplication.class, args); } }
MANIFEST.FM
Manifest-Version: 1.0 Build-Jdk: 17.0.5 Main-Class: ZadanieRekrutacyjne.ZadanieRekrutacyjne.ZadanieRekrutacyjneApplication
application.properties
spring.jpa.hibernate.ddl-auto=update #spring.datasource.url=jdbc:mysql://127.0.0.1:3306/zadanierekrutacyjne spring.datasource.url=jdbc:mysql://host.docker.internal:3307/zadanierekrutacyjne?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false spring.datasource.username=recruit spring.datasource.password=recruit #spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
主类路径:ZadanieRekrutacyjne.ZadanieRekrutacyjne.ZadanieRekrutacyjneApplication
问题分析与解决方案
这个NoClassDefFoundError核心原因是打包后的jar包缺少Spring Boot核心依赖,具体问题出在以下几个方面:
1. Spring Boot版本严重不兼容
- 父pom用的是
2.6.2,但手动指定的starter依赖(如web、thymeleaf、test)用的是3.0.4,Spring Boot 3.x要求Java 17,而你的pom指定的是Java 11,版本完全不匹配,导致依赖冲突,打包时无法正确引入核心类。 - 同时
spring-boot-maven-plugin用的是4.0.1.RELEASE,这也是Spring Boot 3.x的插件版本,和2.6.2的父pom完全不兼容。
解决:统一Spring Boot版本
要么全用2.x,要么升级到3.x并对应Java版本:
- 方案一(保留Java 11):把所有手动指定版本的starter依赖去掉version,让父pom的2.6.2管理版本;同时把spring-boot-maven-plugin版本改为
2.6.2,并移出pluginManagement(因为pluginManagement只是声明,不会实际执行打包)。
修改后的pom.xml关键部分:<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.2</version> <relativePath/> </parent> <!-- 所有starter依赖去掉手动指定的version --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- ...其他同理 --> <build> <!-- 移除pluginManagement,直接配置插件 --> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.2</version> <executions> <execution> <goals> <goal>repackage</goal> <!-- 必须添加这个goal才会生成可执行jar --> </goals> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </execution> </executions> </plugin> </plugins> </build> - 方案二(升级到Spring Boot 3.x):把父pom版本改为
3.0.4,Java版本改为17,插件版本保持3.0.4(注意Spring Boot 3.x的插件版本没有RELEASE后缀),同时mysql-connector-java要改为mysql-connector-j(3.x不再支持旧的artifactId)。
2. Maven打包配置错误
spring-boot-maven-plugin放在了pluginManagement里,这只会声明插件,不会实际执行打包逻辑,导致生成的jar是普通jar,不是Spring Boot的可执行jar(没有包含所有依赖)。- 缺少
repackagegoal,这是Spring Boot插件生成可执行jar的关键步骤。
解决:将插件移出pluginManagement,添加repackage goal
如上面方案一中的修改,确保插件直接在build/plugins下,且包含repackage目标。
3. 手动添加MANIFEST.FM是多余操作
Spring Boot的maven插件会自动生成正确的MANIFEST文件,手动添加的文件会被插件覆盖,反而可能导致混乱,直接删除资源目录下的MANIFEST-INF目录即可。
4. 额外注意:Docker镜像Java版本匹配
如果用方案一(Java 11),Dockerfile要改为FROM openjdk:11,而不是17;如果用方案二(Java 17),则保持openjdk:17。
最后验证步骤
- 执行
mvn clean package,确保打包成功,生成的jar在target目录下。 - 本地先运行
java -jar target/ZadanieRekrutacyjne-0.0.1-SNAPSHOT.jar,确认能正常启动,排除Docker之外的问题。 - 再执行
docker-compose up --build重新构建并运行容器。
内容的提问来源于stack exchange,提问作者Ign
相关产品推荐
相关产品推荐

