JAR 包的打包方式
JAR 包的打包方式
普通JAR vs Fat JAR vs WAR
1. 普通 JAR(默认)-不包含依赖
<packaging>jar</packaging>
会生成普通jar包:xx-1.0-SNAPSHOT.jar - 普通JAR
这种打包方式确实只包含你项目的编译代码,不包含项目pom文件里导入的任何依赖。运行时需要的依赖需要额外提供。
2. Fat JAR - 包含所有依赖
Spring Boot、Quarkus 等框架项目的常见做法
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.0</version> <!-- 添加明确的版本号 -->
</plugin>
</plugins>
</build>
这种 JAR 包会包含所有依赖(除了 provided 范围的),可以直接运行:
java -jar your-app.jar
会生成两个JAR:
your-app.jar# Spring Boot 可执行JAR(包含依赖)your-app.jar.original# 原始JAR(不包含依赖)
普通项目使用 maven-assembly-plugin 或 maven-shade-plugin
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<!-- 需要指定 <mainClass>:否则无法直接运行 java -jar -->
<manifest>
<mainClass>DruidExample</mainClass>
</manifest>
</archive>
</configuration>
<!-- 没有执行配置,插件不会自动运行 -->
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
这种也会创建包含所有依赖的 Fat JAR。会生成两个JAR:
xx-1.0-SNAPSHOT.jar- 普通JARxx-1.0-SNAPSHOT-jar-with-dependencies.jar- 包含依赖的Fat JAR
对比总结
| 特性 | Spring Boot 插件 | Maven Assembly 插件 |
|---|---|---|
| 输出数量 | 1个JAR(新JAR)+ 1个jar.original(原始JAR改名) | 2个JAR(新JAR+原始JAR) |
| 原始JAR | 重命名为 .original |
保留原样 |
| 默认行为 | 替换主JAR | 创建附加JAR |
| 文件命名 | your-app.jar |
your-app-jar-with-dependencies.jar |
如果你想让 Assembly 插件也只生成一个JAR,添加配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId> <!-- 关键配置 -->
</configuration>
</plugin>
为什么 Spring Boot 插件更好?
- 标准的Spring Boot结构:包含
BOOT-INF/classes和BOOT-INF/lib - 更好的类加载:使用Spring Boot的类加载器
- 启动性能优化:支持JAR包索引
- 生产就绪:包含Spring Boot的启动器
所以如果你在用Spring Boot,强烈推荐使用Spring Boot插件,它专门为Spring Boot应用优化过。
3.WAR 包的特殊性
WAR 包确实会自动包含 compile 范围的依赖,但排除 provided 范围的依赖。
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
<scope>provided</scope> <!-- 不会打包进 WAR -->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.0</version>
<!-- 默认 compile,会打包进 WAR -->
</dependency>
</dependencies>
作用域对打包的影响总结
| 作用域 | 普通 JAR | Fat JAR | WAR | 说明 |
|---|---|---|---|---|
compile |
❌ 不包含 | ✅ 包含 | ✅ 包含 | 默认作用域 |
provided |
❌ 不包含 | ❌ 不包含 | ❌ 不包含 | 由运行环境提供 |
runtime |
❌ 不包含 | ✅ 包含 | ✅ 包含 | 运行需要,编译不需要 |
test |
❌ 不包含 | ❌ 不包含 | ❌ 不包含 | 仅测试使用 |
jar包、fat jar包、war包的区别
1. JAR 包 (Java Archive)
- 本质:普通 Java 模块或普通应用的打包结果。
- 内容:只包含你自己写的 编译后的
.class文件 和 配置文件(如application.properties)。不包含 项目依赖的第三方库(如 Spring、JDBC 驱动等)。 - 运行方式:
- 需要机器上提前装好所有依赖。
- 通常作为库被其他项目引用。
- 或者运行一个有
main方法的普通 Java 程序:java -jar app.jar(前提是已经指定了Main-Class)。
- 典型用途:工具类、SDK、基础组件库。
2. FAT JAR 包 (也叫 Uber JAR 或 Shaded JAR)
- 本质:JAR 包的“全包含”升级版。一种自包含、可独立运行的包。
- 内容:包含
你的代码+所有依赖的第三方库(Spring、日志库等) +内嵌的 Web 容器(比如 Spring Boot 内置的 Tomcat、Jetty)。所有这些被解压并重新打包进一个 JAR 文件。 - 运行方式:
java -jar my-app.jar- 不需要外置 Web 容器(不用装 Tomcat),不需要提前下载依赖,一行命令直接运行一个完整的 Web 服务。
- 典型用途:Spring Boot 项目、微服务、云原生应用(一个 jar 就是一个服务)。
3. WAR 包 (Web Application Archive)
- 本质:专门为 部署在外部 Web 容器中 设计的包格式。传统 Java Web 应用的标准格式。
- 内容:
你的代码+依赖的第三方库(lib 目录下) +Web 相关资源(JSP、HTML、web.xml)。不包含 Web 容器(因为容器是外部提供的,如 Tomcat、WebLogic、Jetty)。 - 运行方式:
- 不能直接
java -jar运行。 - 必须先安装 Tomcat、Jetty 等 Web 服务器,然后把 WAR 包放到服务器的
webapps目录下(或用管理界面上传),由服务器启动。
- 不能直接
- 典型用途:传统 Java Web 应用、需要部署到企业级中间件(WebLogic/WebSphere)的项目、包含 JSP 的项目。
快速对比表
| 特性 | JAR | FAT JAR | WAR |
|---|---|---|---|
| 包含依赖 | ❌ 否 | ✅ 是 | ✅ 是 |
| 包含Web容器 | ❌ 否 | ✅ 是 (如内嵌Tomcat) | ❌ 否 (由外部提供) |
| 运行命令 | java -jar xxx.jar (需指定主类) |
java -jar xxx.jar (直接运行Web服务) |
需放到 Tomcat/webapps 下 |
| 启动速度 | 快(但缺依赖) | 较慢(包体积大) | 中等 |
| 包体积 | 很小 | 很大(可能几百MB) | 中等 |
| 典型使用场景 | 基础工具库、SDK | Spring Boot微服务、云原生应用 | 传统Web应用、需要JSP、企业中间件 |
实际经验补充
- 如果你现在学 Spring Boot(主流开发方式),基本只用 FAT JAR。
- 如果你维护 传统 SSM / SSH 项目,或需要 JSP(现在很少用了),大概率用 WAR。
- 如果你写 工具类库 或 非 Web 的后台服务(如定时任务、数据处理),用普通 JAR。
FAT JAR是怎么打出来的?改了maven的底层?
总结:Maven 底层没变,变的是“插件策略”
| 场景 | 使用的插件 | 底层机制 | 结果 |
|---|---|---|---|
| 普通 JAR | maven-jar-plugin(默认) |
只打包自己的类 | 瘦 JAR,运行报错 |
| 手工 FAT JAR | maven-assembly-plugin |
解压所有依赖 -> 合并 -> 打包 | 一个大 JAR,可能有文件覆盖问题 |
| 专业 FAT JAR | maven-shade-plugin |
解压 + 资源合并 + 类重定位 | 可靠的 FAT JAR |
| Spring Boot FAT JAR | spring-boot-maven-plugin |
不解压依赖,保持原样放到 /lib 目录 |
高效的“胖” JAR,结构特殊 |
一句话回答你的问题:
Maven 的底层(生命周期、依赖管理、核心引擎)一个字都没改。FAT JAR 是通过 “替换/配置 Maven 的打包插件” 来实现的。Spring Boot 只是写了一个自己的 Maven 插件,用一种更聪明的布局把依赖 JAR 文件塞进了最终产物里。
浙公网安备 33010602011771号