Docker 部署 Spring Boot 应用:JAR 与 WAR 包的区别及选择
在 Docker 环境中部署 Spring Boot 应用,绝大多数场景推荐直接使用可执行 JAR 包,WAR 包仅在有特殊外部容器依赖时才考虑。
先说结论:Docker 容器化旨在封装完整运行环境,Spring Boot 可执行 JAR 自带内嵌服务器,更符合容器“单进程”原则,WAR 包需额外配置外部容器,会增加镜像复杂度。
- 适合:微服务架构、云原生部署、独立服务场景,直接使用 JAR 包配合轻量级 JDK 基础镜像。
- 重点看:项目是否依赖外部容器的特定配置(如共享资源、JNDI),若无特殊需求,无需引入 WAR 打包。
- 别忽略:若强行在 Docker 中部署 WAR,需额外安装 Tomcat 等容器,违背 Spring Boot 内嵌服务器的设计初衷,增加维护成本。
核心配置差异
JAR 与 WAR 的核心区别在于打包方式及启动类配置,以下是关键配置对比:
1. pom.xml 配置
<!-- 方案一:JAR 包(推荐) -->
<packaging>jar</packaging>
<!-- 无需额外调整依赖 scope -->
<!-- 方案二:WAR 包(需外部容器) -->
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope> <!-- 关键:外部容器提供 Tomcat -->
</dependency>
</dependencies>2. 启动类修改(WAR 包必选)
若使用 WAR 包,主类必须继承 SpringBootServletInitializer 并重写 configure 方法,否则部署到外部 Tomcat 无法启动:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}Dockerfile 构建方案
以下是两种打包方式对应的 Dockerfile 核心差异,注意基础镜像与 Java 版本需与项目编译版本一致:
# 方案一:JAR 包(推荐)
FROM eclipse-temurin:17-jre-alpine
COPY target/app.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 方案二:WAR 包(需外部容器)
FROM tomcat:9-jre11
COPY target/app.war /usr/local/tomcat/webapps/ROOT.war构建与运行步骤
- 确认打包类型:检查
pom.xml中的<packaging>标签。 - 构建应用:使用 Maven 构建产物。
- 构建镜像:生成镜像后启动容器,注意端口映射。
mvn clean package -DskipTestsdocker build -t my-app .
docker run -p 8080:8080 my-app验证方法
- 检查容器状态:使用
docker ps确认容器处于Up状态,无重启循环。 - 查看启动日志:执行
docker logs <container_id>,观察是否有Started Application字样,确认内嵌 Tomcat 启动端口与预期一致。 - 接口测试:在宿主机使用
curl http://localhost:8080/actuator/health或业务接口,确认服务可响应。
常见坑
- 端口冲突:JAR 包默认使用 8080 端口,若宿主机该端口被占用,需在
docker run -p中映射不同宿主机端口,或通过环境变量SERVER_PORT修改应用内部端口。 - 基础镜像版本:确保 Dockerfile 中的 Java 版本与项目编译版本一致(如 Java 17 项目不要用 Java 8 镜像运行),否则会出现
UnsupportedClassVersionError。 - WAR 包配置失效:若误用 WAR 包部署到外部 Tomcat 镜像,
application.properties中的server.port可能不生效,因为端口由外部 Tomcat 的server.xml控制,需额外配置。 - WAR 启动类缺失:WAR 包部署若未继承
SpringBootServletInitializer,外部容器无法识别入口类,导致 404 或启动失败。