Docker化Spring Boot+MySQL应用时Tomcat启动失败求助
问题描述
本地环境下Spring Boot+MySQL项目运行正常,Maven构建也成功,但将应用Docker化并连接MySQL容器时,出现Tomcat无法启动的错误。
Docker化操作步骤
1/ docker pull mysql:5.7 2/ docker run -it --name mysqldb -e MYSQL_ROOT_PASSWORD=test -p 3308:3308 mysql:5.7 3/ docker exec -it mysqldb bash 4/ 创建数据库 5/ docker exec -i mysqldb mysql -uroot -ptest quizgame <quizgame.sql 6/ mvnw.cmd clean install -DskipTests 7/ docker build -f Dockerfile -t gamezquizapp . 8/ docker run -t --link mysqldb -p 8099:8099 gamezquizapp
错误栈关键信息
13:58:03.743 [main] ERROR o.s.boot.SpringApplication - Application run failed org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163) ...(省略部分栈信息) Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager
配置文件
Application.properties
server.port=8099 ### DATABASE ### debug=true spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://mysqldb:3308/quizgame?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=test ### JPA / HIBERNATE ### spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true bezkoder.app.jwtSecret= ***** bezkoder.app.jwtExpirationMs= **** spring.mail.host=**** spring.mail.port=*** spring.mail.username=**** spring.mail.password=**** spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.connectiontimeout=5000 spring.mail.properties.mail.smtp.timeout=5000 spring.mail.properties.mail.smtp.writetimeout=5000 spring.mail.properties.mail.smtp.starttls.enable=true closeMethod="close"/> # Max file size. spring.servlet.multipart.max-file-size=20MB # Max Request Size spring.servlet.multipart.max-request-size=20MB
Dockerfile
FROM openjdk:8 COPY . . EXPOSE 8099 ENTRYPOINT ["java","-jar","target/QuizGameApp-1.0.jar" ]
.env文件
MYSQLDB_USER=root MYSQLDB_ROOT_PASSWORD=test MYSQLDB_DATABASE=quizgame MYSQLDB_LOCAL_PORT=3308 MYSQLDB_DOCKER_PORT=3308 SPRING_LOCAL_PORT=8099 SPRING_DOCKER_PORT=8099
问题排查与解决
1. 核心错误分析
NoClassDefFoundError说明JVM找不到ValueExtractorManager类,根源通常是依赖缺失/版本不兼容、JDK与依赖库不匹配、Docker构建的jar包不完整这三类问题。结合你的操作步骤,逐一排查如下:
2. 具体修复点
(1)修正MySQL容器端口配置
你运行MySQL容器时用了-p 3308:3308,但MySQL默认容器内端口是3306,强行映射3308会导致容器内MySQL服务无法正常启动,这既是数据库连接的隐患,也可能间接引发应用启动异常。
修复:
- 删除旧MySQL容器,重新运行并映射正确端口:
docker stop mysqldb && docker rm mysqldb docker run -d --name mysqldb -e MYSQL_ROOT_PASSWORD=test -p 3308:3306 mysql:5.7
- 修改
application.properties中的数据库URL端口为3306:
spring.datasource.url=jdbc:mysql://mysqldb:3306/quizgame?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
(2)修复Docker构建的jar包问题
你的Dockerfile直接复制本地所有文件,可能存在本地构建的jar包不是完整的可执行fat jar(未包含所有依赖),或者Windows环境构建的jar包在Linux容器中出现兼容性问题。
修复:
- 确保
pom.xml中配置Spring Boot Maven插件,生成包含所有依赖的fat jar:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 修改Dockerfile为多阶段构建,在容器内完成Maven构建,避免本地环境干扰:
# 构建阶段:在Maven镜像中编译打包 FROM maven:3.8.6-openjdk-8 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests # 运行阶段:仅复制最终jar包到轻量JDK镜像 FROM openjdk:8 WORKDIR /app COPY --from=builder /app/target/QuizGameApp-1.0.jar . EXPOSE 8099 ENTRYPOINT ["java", "-jar", "QuizGameApp-1.0.jar"]
(3)移除无效配置项
你的application.properties末尾有一行无效的XML标签 closeMethod="close"/>,会导致Spring配置解析失败,间接引发Tomcat启动异常。
修复:直接删除该行无效配置。
(4)优化Docker网络连接
--link是Docker旧特性,建议改用自定义网络确保容器间通信稳定:
# 创建自定义网络 docker network create game-network # 重新运行MySQL容器加入网络 docker stop mysqldb && docker rm mysqldb docker run -d --name mysqldb --network game-network -e MYSQL_ROOT_PASSWORD=test -p 3308:3306 mysql:5.7 # 导入数据库(等待MySQL启动完成后执行) docker exec -i mysqldb mysql -uroot -ptest quizgame <quizgame.sql # 运行Spring Boot容器时加入同一网络 docker run -d --name gamezquizapp --network game-network -p 8099:8099 gamezquizapp
3. 完整修复流程
- 修正
application.properties的数据库端口和无效配置。 - 确保
pom.xml配置Spring Boot Maven插件。 - 更新Dockerfile为多阶段构建。
- 删除旧容器,创建自定义网络,重新启动MySQL并导入数据库。
- 重新构建Spring Boot镜像并启动容器。
内容的提问来源于stack exchange,提问作者Houssem
相关产品推荐
相关产品推荐

