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 - 普通JAR
  • xx-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 插件更好?

  1. 标准的Spring Boot结构:包含 BOOT-INF/classesBOOT-INF/lib
  2. 更好的类加载:使用Spring Boot的类加载器
  3. 启动性能优化:支持JAR包索引
  4. 生产就绪:包含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 文件塞进了最终产物里。

posted @ 2025-11-27 20:29  deyang  阅读(191)  评论(0)    收藏  举报