📦 第11章 SpringBoot 打包

掌握SpringBoot应用打包部署 - 从Fat JAR到容器化

学习进度:11/23 章节 (48%)

💻 查看完整代码 - 在线IDE体验

🎯 本章学习目标

  • 理解SpringBoot打包机制
  • 掌握Fat JAR打包原理
  • 学会War包部署方式
  • 掌握Docker容器化部署
  • 了解原生镜像构建技术

⏰ 预计学习时间

3小时(理论学习 + 多种打包方式实践)

🏗️ SpringBoot打包概述

打包的重要性:

  • 部署便利:一键部署到任何环境
  • 依赖管理:包含所有必需依赖
  • 环境一致:避免环境差异问题
  • 运维友好:简化运维部署流程

SpringBoot打包优势:

传统应用部署:应用 + 应用服务器 + 配置 ↓ SpringBoot部署:Fat JAR(应用 + 内嵌服务器 + 配置) ↓ 一个文件搞定所有部署需求

💡 核心理念

SpringBoot的"约定优于配置"理念在打包部署中体现得淋漓尽致

📋 打包方式对比

SpringBoot支持多种打包方式,适应不同的部署场景

Fat JAR 打包
特点:包含所有依赖的可执行JAR
适用场景:微服务、云原生应用
启动方式:java -jar app.jar
# Maven打包命令 mvn clean package # 生成的文件 target/myapp-1.0.0.jar
WAR 打包
特点:传统Web应用打包格式
适用场景:外部Tomcat部署
部署方式:部署到应用服务器
# pom.xml配置 <packaging>war</packaging> # 生成的文件 target/myapp-1.0.0.war
Docker 容器化
特点:容器化部署,环境隔离
适用场景:云原生、微服务架构
部署方式:Docker容器运行
# Dockerfile FROM openjdk:11-jre-slim COPY target/app.jar app.jar ENTRYPOINT ["java","-jar","/app.jar"]
原生镜像
特点:编译为原生可执行文件
适用场景:高性能、快速启动
技术:GraalVM Native Image
# 原生镜像构建 mvn -Pnative native:compile # 生成原生可执行文件 target/myapp

🎯 Fat JAR 详解

Fat JAR 结构:

myapp-1.0.0.jar ├── BOOT-INF/ │ ├── classes/ # 应用程序类 │ │ └── com/example/MyApp.class │ ├── lib/ # 依赖JAR包 │ │ ├── spring-boot-2.7.0.jar │ │ ├── spring-core-5.3.21.jar │ │ └── ... │ └── classpath.idx # 类路径索引 ├── META-INF/ │ ├── MANIFEST.MF # 清单文件 │ └── maven/ └── org/ └── springframework/ └── boot/ └── loader/ # SpringBoot加载器 ├── JarLauncher.class └── ...

Maven配置:

<!-- pom.xml --> <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打包:

<!-- pom.xml --> <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:

# 1. 打包WAR文件 $ mvn clean package # 2. 复制到Tomcat webapps目录 $ cp target/myapp-1.0.0.war $TOMCAT_HOME/webapps/ # 3. 启动Tomcat $ $TOMCAT_HOME/bin/startup.sh # 4. 访问应用 $ curl http://localhost:8080/myapp-1.0.0/

🐳 Docker 容器化

基础Dockerfile:

# Dockerfile FROM openjdk:11-jre-slim # 设置工作目录 WORKDIR /app # 复制JAR文件 COPY target/myapp-1.0.0.jar app.jar # 暴露端口 EXPOSE 8080 # 设置JVM参数 ENV JAVA_OPTS="-Xmx512m -Xms256m" # 启动应用 ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

多阶段构建:

# 多阶段Dockerfile # 构建阶段 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

🚀 部署选项

独立部署
直接在服务器上运行JAR文件
适合小型应用和开发环境
容器部署
使用Docker容器运行应用
环境隔离,易于扩展
云平台部署
部署到AWS、Azure、阿里云
弹性伸缩,高可用性
Kubernetes
容器编排平台部署
自动化运维,服务发现

⚙️ 高级打包配置

自定义打包配置:

<!-- Maven插件高级配置 --> <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:

# 启用分层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配置:

<!-- pom.xml --> <profiles> <profile> <id>native</id> <build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> </plugin> </plugins> </build> </profile> </profiles>

构建原生镜像:

# 安装GraalVM $ sdk install java 22.3.r11-grl $ sdk use java 22.3.r11-grl # 安装native-image $ 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是最通用的选择

🎉 恭喜完成第11章学习!

你已经掌握了SpringBoot应用的各种打包部署方式,接下来让我们深入学习自动装配原理。

📚 进入第12章:SpringBoot 自动装配 ⬅️ 返回第10章 🏠 返回课程首页