Spring Boot 提供了灵活的打包选项,支持两种主要部署方式:可执行 JAR传统 WAR。以下是全面的对比与实践指南,帮助你根据项目需求选择最适合的部署方案。


📦 一、打包方式对比

特性可执行 JAR (默认)传统 WAR
启动方式java -jar app.jar部署到外部 Servlet 容器 (如 Tomcat)
内嵌服务器✅ 包含 Tomcat/Jetty/Undertow❌ 需外部容器
部署复杂度⭐ 极简 (单文件部署)⭐⭐⭐ 需容器环境
依赖管理所有依赖打包进单个 FAT JAR依赖由容器管理 (部分依赖可打包进 WAR)
热更新需第三方工具 (JRebel)支持容器级热部署
生产适用场景微服务/云原生环境传统企业级应用服务器环境
文件大小较大 (包含内嵌容器)较小 (仅应用代码)

🛠️ 二、JAR 打包部署 (默认方式)

1. 打包配置 (Maven)

确保你的 pom.xml 文件中有如下插件配置:

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

2. 打包命令

使用 Maven 进行构建:

1
2
mvn clean package
# 生成 target/appname-0.0.1-SNAPSHOT.jar

3. 运行方式

可以采用多种方式运行 JAR 文件:

1
2
3
4
5
6
7
8
# 标准启动
java -jar app.jar

# 带配置文件启动
java -jar -Dspring.profiles.active=prod app.jar

# 内存限制启动
java -Xms512m -Xmx1024m -jar app.jar

4. 生产环境增强

为了更好地适应生产环境,你可以采取以下措施:

  • 系统服务化 (Systemd):
1
2
3
4
5
6
7
8
[Unit]
Description=Spring Boot Service
After=syslog.target

[Service]
User=appuser
ExecStart=/usr/bin/java -jar /opt/app/app.jar
SuccessExitStatus=143
  • 启动脚本封装 (带日志分割):
1
nohup java -jar app.jar > app.log 2>&1 &

🧩 三、WAR 打包部署 (传统方式)

1. 修改打包类型

首先,在 pom.xml 中将 <packaging> 修改为 war

1
<packaging>war</packaging>

2. 排除内嵌容器 (Tomcat)

由于 WAR 文件需要部署到外部容器中,因此需要排除内置的 Tomcat:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

3. 初始化 Servlet 入口

修改主类以继承 SpringBootServletInitializer

1
2
3
4
5
6
7
8
9
10
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

4. 构建与部署

完成上述步骤后,执行打包命令并部署到 Tomcat:

1
2
3
4
5
mvn clean package
# 生成 target/appname-0.0.1-SNAPSHOT.war

# 部署到 Tomcat
cp target/app.war $TOMCAT_HOME/webapps/

☁️ 四、云原生部署最佳实践

1. Docker 容器化部署 (JAR 方式)

编写 Dockerfile 来创建镜像:

1
2
3
4
FROM eclipse-temurin:17-jre
VOLUME /tmp
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

然后构建和运行 Docker 镜像:

1
2
docker build -t myapp:1.0 .
docker run -d -p 8080:8080 myapp:1.0

2. 多阶段构建优化镜像

利用多阶段构建来减小最终镜像体积:

1
2
3
4
5
6
7
8
9
10
11
# 阶段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 部署:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-app
spec:
replicas: 3
selector:
matchLabels:
app: springboot
template:
metadata:
labels:
app: springboot
spec:
containers:
- name: app
image: myregistry/springboot-app:1.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: springboot-service
spec:
selector:
app: springboot
ports:
- protocol: TCP
port: 80
targetPort: 8080

⚠️ 五、关键注意事项

  1. 静态资源处理
    JAR 模式:资源放在 src/main/resources/static
    WAR 模式:资源放在 src/main/webapp

  2. 配置文件优先级
    Spring Boot 加载顺序:

    1. jar 内部 application.properties
    2. jar 同级 /config/ 目录
    3. jar 同级目录
    4. 类路径 /config
    5. 类路径根目录
  3. 上下文路径设置
    JAR 模式:server.servlet.context-path=/api
    WAR 模式:通过容器设置或 application.properties

  4. 端口冲突解决

1
2
# 避免与容器端口冲突
server.port=8081
  1. WAR 部署常见问题
    类冲突:使用 <scope>provided</scope> 排除容器已有库
    路径错误:确保 SpringBootServletInitializer 正确配置

🔍 六、部署决策树


🚀 七、高级部署方案

  1. 性能优化启动
1
2
# 开启 AOT 优化 (Spring Boot 3+)
java -Dspring.aot.enabled=true -jar app.jar
  1. GraalVM 原生镜像
1
2
# 需配置 spring-boot-starter-parent 3.x
mvn native:compile -Pnative
  1. 蓝绿部署方案

  1. 健康检查端点
1
2
3
4
5
6
7
8
9
10
management:
endpoint:
health:
probes:
enabled: true # 启用K8s就绪/存活检查
health:
livenessstate:
enabled: true
readinessstate:
enabled: true

💎 总结建议

  • 优先选择 JAR: 对于大多数微服务和云原生应用来说,JAR 是理想的选择。
  • 选择 WAR 当: 需要与遗留系统集成或必须在特定应用服务器上运行时考虑使用 WAR。