Spring Boot 部署与打包方式详解(Jar vs War)
Spring Boot 提供了灵活的打包选项,支持两种主要部署方式:可执行 JAR 和 传统 WAR。以下是全面的对比与实践指南,帮助你根据项目需求选择最适合的部署方案。
📦 一、打包方式对比
特性 | 可执行 JAR (默认) | 传统 WAR |
---|---|---|
启动方式 | java -jar app.jar | 部署到外部 Servlet 容器 (如 Tomcat) |
内嵌服务器 | ✅ 包含 Tomcat/Jetty/Undertow | ❌ 需外部容器 |
部署复杂度 | ⭐ 极简 (单文件部署) | ⭐⭐⭐ 需容器环境 |
依赖管理 | 所有依赖打包进单个 FAT JAR | 依赖由容器管理 (部分依赖可打包进 WAR) |
热更新 | 需第三方工具 (JRebel) | 支持容器级热部署 |
生产适用场景 | 微服务/云原生环境 | 传统企业级应用服务器环境 |
文件大小 | 较大 (包含内嵌容器) | 较小 (仅应用代码) |
🛠️ 二、JAR 打包部署 (默认方式)
1. 打包配置 (Maven)
确保你的 pom.xml
文件中有如下插件配置:
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>
2. 打包命令
使用 Maven 进行构建:
mvn clean package
# 生成 target/appname-0.0.1-SNAPSHOT.jar
3. 运行方式
可以采用多种方式运行 JAR 文件:
# 标准启动
java -jar app.jar# 带配置文件启动
java -jar -Dspring.profiles.active=prod app.jar# 内存限制启动
java -Xms512m -Xmx1024m -jar app.jar
4. 生产环境增强
为了更好地适应生产环境,你可以采取以下措施:
- 系统服务化 (Systemd):
[Unit]
Description=Spring Boot Service
After=syslog.target[Service]
User=appuser
ExecStart=/usr/bin/java -jar /opt/app/app.jar
SuccessExitStatus=143
- 启动脚本封装 (带日志分割):
nohup java -jar app.jar > app.log 2>&1 &
🧩 三、WAR 打包部署 (传统方式)
1. 修改打包类型
首先,在 pom.xml
中将 <packaging>
修改为 war
:
<packaging>war</packaging>
2. 排除内嵌容器 (Tomcat)
由于 WAR 文件需要部署到外部容器中,因此需要排除内置的 Tomcat:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope>
</dependency>
3. 初始化 Servlet 入口
修改主类以继承 SpringBootServletInitializer
:
public class Application extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(Application.class);}public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
4. 构建与部署
完成上述步骤后,执行打包命令并部署到 Tomcat:
mvn clean package
# 生成 target/appname-0.0.1-SNAPSHOT.war# 部署到 Tomcat
cp target/app.war $TOMCAT_HOME/webapps/
☁️ 四、云原生部署最佳实践
1. Docker 容器化部署 (JAR 方式)
编写 Dockerfile 来创建镜像:
FROM eclipse-temurin:17-jre
VOLUME /tmp
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
然后构建和运行 Docker 镜像:
docker build -t myapp:1.0 .
docker run -d -p 8080:8080 myapp:1.0
2. 多阶段构建优化镜像
利用多阶段构建来减小最终镜像体积:
# 阶段1:构建应用
FROM maven:3.8.6 AS build
COPY src /app/src
COPY pom.xml /app
RUN mvn -f /app/pom.xml clean package# 阶段2:运行镜像
FROM eclipse-temurin:17-jre-alpine
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
3. Kubernetes 部署
定义 Deployment 和 Service YAML 文件来进行 Kubernetes 部署:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: springboot-app
spec:replicas: 3selector:matchLabels:app: springboottemplate:metadata:labels:app: springbootspec:containers:- name: appimage: myregistry/springboot-app:1.0ports:- containerPort: 8080env:- name: SPRING_PROFILES_ACTIVEvalue: prod
---
# service.yaml
apiVersion: v1
kind: Service
metadata:name: springboot-service
spec:selector:app: springbootports:- protocol: TCPport: 80targetPort: 8080
⚠️ 五、关键注意事项
-
静态资源处理
JAR 模式:资源放在src/main/resources/static
WAR 模式:资源放在src/main/webapp
-
配置文件优先级
Spring Boot 加载顺序:
1. jar 内部 application.properties
2. jar 同级 /config/ 目录
3. jar 同级目录
4. 类路径 /config
5. 类路径根目录
-
上下文路径设置
JAR 模式:server.servlet.context-path=/api
WAR 模式:通过容器设置或application.properties
-
端口冲突解决
# 避免与容器端口冲突
server.port=8081
- WAR 部署常见问题
类冲突:使用<scope>provided</scope>
排除容器已有库
路径错误:确保SpringBootServletInitializer
正确配置
🔍 六、部署决策树
🚀 七、高级部署方案
- 性能优化启动
# 开启 AOT 优化 (Spring Boot 3+)
java -Dspring.aot.enabled=true -jar app.jar
- GraalVM 原生镜像
# 需配置 spring-boot-starter-parent 3.x
mvn native:compile -Pnative
- 蓝绿部署方案
- 健康检查端点
management:endpoint:health:probes:enabled: true # 启用K8s就绪/存活检查health:livenessstate:enabled: truereadinessstate:enabled: true
💎 总结建议
- 优先选择 JAR: 对于大多数微服务和云原生应用来说,JAR 是理想的选择。
- 选择 WAR 当: 需要与遗留系统集成或必须在特定应用服务器上运行时考虑使用 WAR。
- 如果你在学习过程中遇到任何问题,欢迎在评论区留言交流!
- 👍 如果你觉得这篇文章对你有帮助,别忘了点赞、收藏、转发哦!