🎯 本章学习目标
- 理解SpringBoot打包机制
- 掌握Fat JAR打包原理
- 学会War包部署方式
- 掌握Docker容器化部署
- 了解原生镜像构建技术
⏰ 预计学习时间
3小时(理论学习 + 多种打包方式实践)
🏗️ SpringBoot打包概述
打包的重要性:
- 部署便利:一键部署到任何环境
- 依赖管理:包含所有必需依赖
- 环境一致:避免环境差异问题
- 运维友好:简化运维部署流程
SpringBoot打包优势:
传统应用部署:应用 + 应用服务器 + 配置
↓
SpringBoot部署:Fat JAR(应用 + 内嵌服务器 + 配置)
↓
一个文件搞定所有部署需求
💡 核心理念
SpringBoot的"约定优于配置"理念在打包部署中体现得淋漓尽致
🎯 Fat JAR 详解
Fat JAR 结构:
myapp-1.0.0.jar
├── BOOT-INF/
│ ├── classes/
│ │ └── com/example/MyApp.class
│ ├── lib/
│ │ ├── spring-boot-2.7.0.jar
│ │ ├── spring-core-5.3.21.jar
│ │ └── ...
│ └── classpath.idx
├── META-INF/
│ ├── MANIFEST.MF
│ └── maven/
└── org/
└── springframework/
└── boot/
└── loader/
├── JarLauncher.class
└── ...
Maven配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.MyApplication</mainClass>
<layout>JAR</layout>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
打包和运行命令:
$ mvn clean package
[INFO] Building jar: target/myapp-1.0.0.jar
$ java -jar target/myapp-1.0.0.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
$ java -jar -Dspring.profiles.active=prod target/myapp-1.0.0.jar
🌐 WAR 包部署
配置WAR打包:
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
启动类配置:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application
) {
return application.sources(MyApplication.class);
}
}
部署到Tomcat:
$ mvn clean package
$ cp target/myapp-1.0.0.war $TOMCAT_HOME/webapps/
$ $TOMCAT_HOME/bin/startup.sh
$ curl http://localhost:8080/myapp-1.0.0/
🐳 Docker 容器化
基础Dockerfile:
FROM openjdk:11-jre-slim
WORKDIR /app
COPY target/myapp-1.0.0.jar app.jar
EXPOSE 8080
ENV JAVA_OPTS="-Xmx512m -Xms256m"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
多阶段构建:
FROM maven:3.8.4-openjdk-11 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /app/target/myapp-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Docker命令:
$ docker build -t myapp:1.0.0 .
$ docker run -d -p 8080:8080 --name myapp myapp:1.0.0
$ docker logs -f myapp
$ docker exec -it myapp /bin/bash
⚙️ 高级打包配置
自定义打包配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
<mainClass>com.example.MyApplication</mainClass>
<layout>JAR</layout>
<includes>
<include>
<groupId>com.example</groupId>
<artifactId>my-library</artifactId>
</include>
</includes>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
分层JAR:
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
java -Djarmode=layertools -jar myapp.jar list
java -Djarmode=layertools -jar myapp.jar extract
优化的Dockerfile(分层):
FROM openjdk:11-jre-slim as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM openjdk:11-jre-slim
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
🔧 性能优化
JVM参数优化:
java -Xmx1g -Xms512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-jar myapp.jar
java -XX:+TieredCompilation \
-XX:TieredStopAtLevel=1 \
-noverify \
-jar myapp.jar
java -server \
-Xmx2g -Xms2g \
-XX:+UseG1GC \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/heapdump.hprof \
-Dspring.profiles.active=prod \
-jar myapp.jar
应用优化:
- 移除不必要的依赖
- 使用Spring Boot的懒加载
- 优化自动配置
- 使用Profile分离配置
⚠️ 注意事项
生产环境部署时要注意安全配置,如禁用开发工具、设置合适的日志级别等
⚡ 原生镜像构建
GraalVM配置:
<profiles>
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
构建原生镜像:
$ sdk install java 22.3.r11-grl
$ sdk use java 22.3.r11-grl
$ gu install native-image
$ mvn -Pnative native:compile
$ ./target/myapp
原生镜像优势:
- 极快的启动时间(毫秒级)
- 更低的内存占用
- 更小的镜像体积
- 无需JVM运行时
📊 打包方式对比
性能对比:
打包方式 | 启动时间 | 内存占用 | 文件大小 | 部署复杂度
----------|---------|---------|---------|----------
Fat JAR | 3-5秒 | 200MB | 50MB | 简单
WAR | 5-10秒 | 300MB | 45MB | 中等
Docker | 3-5秒 | 250MB | 200MB | 中等
Native | 0.1秒 | 50MB | 80MB | 复杂
选择建议:
- Fat JAR:微服务、云原生应用首选
- WAR:传统企业环境,已有Tomcat
- Docker:容器化部署,DevOps环境
- Native:对启动时间要求极高的场景
💡 最佳实践
根据实际部署环境和性能要求选择合适的打包方式,Fat JAR是最通用的选择