为什么 Spring Boot 应用倾向于打 fat jar 直接启动,而早期企业应用倾向于打 war 包从应用容器启动?
Spring Boot选择Fat Jar的本质原因
-
与DevOps理念的契合
-
交付单元标准化
Fat Jar将应用+容器+依赖封装为单一可执行单元,符合"Build once, deploy anywhere"的DevOps原则
-
部署流程简化
消除传统WAR包与容器间的环境耦合,
java -jar
即可启动,适合CI/CD流水线 -
版本控制明确
容器版本与应用版本绑定,避免"运维独立升级容器导致兼容性问题"的经典痛点
-
-
云原生时代的必然选择
-
不可变基础设施要求
Fat Jar作为原子构建产物,完美匹配容器镜像的不可变性要求(Dockerfile中只需COPY+ENTRYPOINT)
-
微服务架构适配
单个服务独立部署时,轻量级Fat Jar比传统容器更节省资源(如Spring Boot内嵌Tomcat仅30MB左右)
-
技术演进路线图
graph LR A[物理机时代] --> B[虚拟机时代] --> C[容器化时代] A -->|J2EE规范| D[共享应用容器] D -->|多WAR混部| E[资源利用率优化] B -->|隔离需求| F[单虚拟机单容器] C -->|不可变基础设施| G[Fat Jar+容器镜像] F -->|配置管理复杂| G
关键转折点
-
J2EE规范的影响(2000s)
-
设计目标
通过标准化接口实现"Write once, run anywhere"
-
副作用
催生臃肿的应用服务器(WebLogic/WebSphere),部署复杂度反噬开发效率
-
-
虚拟化技术的双重作用(2010s)
-
积极面
资源隔离使"单VM单容器"模式可行
-
遗留问题
VM镜像仍包含可变状态(如配置文件),违背Immutable原则
-
-
Docker的范式革命(2013年后)
-
镜像分层
Fat Jar作为应用层,与基础镜像解耦
-
启动速度
容器秒级启动 vs 传统容器分钟级启动,使"拆分为微服务"成为可能
-
行业思潮映射表
时代 | 核心诉求 | 技术方案 | 代表产物 |
---|---|---|---|
前云计算 | 硬件资源最大化利用 | 共享容器+多WAR混部 | Tomcat集群 |
DevOps早期 | 部署流程自动化 | 内嵌容器+Fat Jar | Spring Boot 1.x |
云原生时代 | 基础设施不可变 | 容器镜像+声明式配置 | Kubernetes |
未来演进方向
-
GraalVM原生镜像
-
更极端的Fat Jar
将JVM也打包进去,生成原生二进制
-
启动时间从秒级降至毫秒级(如Quarkus框架)
-
-
Serverless演进
-
Fat Jar转变为Function as a Unit
-
案例
AWS Lambda的Java运行时要求zip包含所有依赖
-
-
配置管理的终极形态
-
从环境变量到ConfigMap,再到Operator模式
-
最新趋势
GitOps将配置也纳入版本控制
-