Docker 部署 Spring Boot 应用用 jar 还是 war 包区别

文章导读
在 Docker 环境中部署 Spring Boot 应用,绝大多数场景推荐直接使用可执行 JAR 包,WAR 包仅在有特殊外部容器依赖时才考虑。
📋 目录
  1. A 核心配置差异
  2. B Dockerfile 构建方案
  3. C 构建与运行步骤
  4. D 验证方法
  5. E 常见坑
A A

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 配置

Docker 部署 Spring Boot 应用用 jar 还是 war 包区别
<!-- 方案一: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

构建与运行步骤

  1. 确认打包类型:检查 pom.xml 中的 <packaging> 标签。
  2. 构建应用:使用 Maven 构建产物。
  3. mvn clean package -DskipTests
  4. 构建镜像:生成镜像后启动容器,注意端口映射。
  5. docker build -t my-app .
    docker run -p 8080:8080 my-app

验证方法

  1. 检查容器状态:使用 docker ps 确认容器处于 Up 状态,无重启循环。
  2. 查看启动日志:执行 docker logs <container_id>,观察是否有 Started Application 字样,确认内嵌 Tomcat 启动端口与预期一致。
  3. 接口测试:在宿主机使用 curl http://localhost:8080/actuator/health 或业务接口,确认服务可响应。

常见坑

  1. 端口冲突:JAR 包默认使用 8080 端口,若宿主机该端口被占用,需在 docker run -p 中映射不同宿主机端口,或通过环境变量 SERVER_PORT 修改应用内部端口。
  2. 基础镜像版本:确保 Dockerfile 中的 Java 版本与项目编译版本一致(如 Java 17 项目不要用 Java 8 镜像运行),否则会出现 UnsupportedClassVersionError
  3. WAR 包配置失效:若误用 WAR 包部署到外部 Tomcat 镜像,application.properties 中的 server.port 可能不生效,因为端口由外部 Tomcat 的 server.xml 控制,需额外配置。
  4. WAR 启动类缺失:WAR 包部署若未继承 SpringBootServletInitializer,外部容器无法识别入口类,导致 404 或启动失败。