优秀的编程知识分享平台

网站首页 > 技术文章 正文

Spring Boot 3 中 Jar 的运行原理及解压后文件含义

nanyue 2025-09-04 14:17:26 技术文章 7 ℃

在互联网软件开发领域,Spring Boot 框架以其便捷高效的开发体验,深受广大开发者的喜爱。其中,Spring Boot 3 中可执行 Jar 包的特性更是为项目的部署和运行带来了极大的便利。今天,我们就来深入探讨一下 Spring Boot 3 中 Jar 的运行原理,以及解压 Jar 包之后各个文件的含义。

Spring Boot Jar 包的独特之处

传统 Java 应用的 JAR 包在依赖管理上存在明显短板,依赖项需要单独配置 classpath,这无疑增加了开发和部署的复杂性。而 Spring Boot 创新地提出了 Fat JAR(又称 Uber JAR)解决方案,通过 spring-boot-maven-plugin 插件实现了 "All - in - One" 打包模式 。这一模式具有以下显著优势:

嵌入式依赖管理:将所有第三方库打包至 BOOT - INF/lib 目录,使得依赖管理变得更加简单和集中。

独立运行能力:内置启动加载器,无需外部容器,大大简化了应用的部署过程。

统一资源管理:项目资源与依赖资源隔离存放,避免了资源冲突的问题。

Spring Boot 应用的打包机制

(一)Maven 构建过程

在使用 Maven 构建 Spring Boot 应用时,spring - boot - maven - plugin 插件发挥着关键作用。当我们执行 mvn package 命令时,整个构建过程如下:

Maven 标准打包:首先,Maven 按照标准流程生成原始 JAR,这个 JAR 只包含了项目自身编译后的类文件和资源。

插件二次封装:接着,spring - boot - maven - plugin 插件执行 repackage 目标,对原始 JAR 进行二次封装。在这个过程中,插件会将项目的所有依赖项,包括 Spring Boot starter 依赖以及其他第三方库,一同打包进 JAR 中,最终生成可执行的 Fat JAR。同时,原始 JAR 会被保留为 *.jar.original。

spring - boot - maven - plugin 插件还提供了其他一些有用的目标,例如:

  • build - info:生成 build - info.properties 构建信息文件,方便在 CI/CD 流水线中集成。
  • run:可以直接运行 Spring Boot 应用,非常适合本地开发调试。

(二)Gradle 构建过程

如果使用 Gradle 构建 Spring Boot 应用,也有相应的插件来实现类似的功能。通过在 build.gradle 文件中配置相关插件和依赖,同样可以将项目及其依赖打包成可执行的 Jar 包。其核心思想与 Maven 构建类似,都是为了创建一个自包含的、可独立运行的应用包。

解压 Spring Boot Jar 包后的目录结构解析

当我们解压一个 Spring Boot 3 的可执行 Jar 包时,会看到以下目录结构:

BOOT - INF/classes:这个目录存放着应用编译后的 class 文件,也就是我们编写的业务代码以及相关的配置文件经过编译后的结果。这里面包含了所有定义的类、接口、枚举等,是应用运行的核心代码部分。例如,我们定义的 Controller 类、Service 类、Entity 类等,它们的字节码文件都存放在此目录下相应的包结构中。

BOOT - INF/lib:该目录放置了应用依赖的所有第三方 JAR 包文件。Spring Boot 应用的各种功能实现往往依赖于众多的第三方库,比如数据库连接池依赖的 HikariCP 库、JSON 处理依赖的 Jackson 库等,这些库的 JAR 包都被统一放置在这个目录中。这也是 Spring Boot Fat JAR 实现 “All - in - One” 的重要体现,将所有依赖集中管理,避免了因依赖散落各处而导致的类路径配置错误。

META - INF:此目录存放着应用打包信息,包括 Maven 坐标、pom 文件(记录了项目的依赖关系等信息),以及至关重要的 MANIFEST.MF 文件。MANIFEST.MF 文件包含了关于 JAR 包的基本信息和运行指令,其中定义了 Main - Class 属性,指定了用于启动整个应用程序的类,通常是
org.springframework.boot.loader.JarLauncher 。同时,还可能包含 Start - Class 属性,它定义了我们项目的实际启动类,也就是带有 @SpringBootApplication 注解的类。

org:该目录存放 Spring Boot 相关 class 文件,主要是 Spring Boot 框架自身的一些核心类和工具类,这些类为 Spring Boot 应用的运行提供了底层支持,例如类加载机制、自动配置功能等的实现类。

Spring Boot Jar 的运行原理

(一)启动器类加载机制

当我们使用 java - jar 命令运行 Spring Boot 应用的可执行 Jar 文件时,整个启动过程如下:

  1. 读取 MANIFEST.MF:JVM 首先引导标准可执行的 jar 文件,读取在 jar 中 META - INF/MANIFEST.MF 文件的 Main - Class 属性值。在 Spring Boot 应用中,这个值通常指向 org.springframework.boot.loader.JarLauncher 。
  2. 启动 JarLauncher:JarLauncher 类是 Spring Boot 自定义的类加载器体系的一部分,它继承自 org.springframework.boot.loader.Launcher 。JarLauncher 的 main 方法被调用后,会创建一个自定义的类加载器,通常是 LaunchedURLClassLoader 。
  3. 加载应用资源:LaunchedURLClassLoader 会将 BOOT - INF/classes 下的类文件和 BOOT - INF/lib 下依赖的 jar 加入到 classpath 下。它通过分析 Fat JAR 的内部结构,构造出一系列的 URL,这些 URL 指向 Jar 包中的各个依赖和资源路径。然后,使用这些 URL 创建类加载器,并最终通过反射调用 META - INF/MANIFEST.MF 文件 Start - Class 属性指定的类,也就是我们项目的主启动类(带有 @SpringBootApplication 注解的类)的 main 方法,从而启动应用程序。

(二)自定义类加载器的优势

Spring Boot 自定义的类加载器,如 LaunchedURLClassLoader,具有以下优势:

  1. 类加载隔离:通过自定义类加载器,可以避免不同依赖之间的类冲突问题。每个依赖库都可以在自己的类加载空间中被加载,确保了类的独立性和安全性。
  2. 启动加速:可以实现并行加载依赖,提升应用的启动速度。在启动过程中,多个依赖库可以同时被加载,而不是按照顺序逐个加载,大大缩短了应用从启动到可用的时间。
  3. 支持嵌套 JAR 加载:传统的 JDK 中,JarFile 的 URL 协议只支持一层 “!/” 来表示 Jar 包内的资源路径,无法加载嵌套在 Jar 包中的 Jar 包。而 Spring Boot 扩展了这一机制,通过自定义的 URLStreamHandler 和 JarURLConnection 实现类,支持多层嵌套的资源路径,如 jar:file:app.jar!/BOOT - INF/lib/dependency.jar!/ ,从而可以访问嵌套 Jar 包中的资源。

总结

通过深入了解 Spring Boot 3 中 Jar 的运行原理以及解压后各个文件的含义,我们可以更好地优化应用架构设计,提升部署效率,并有效排查类加载相关的问题。在实际开发中,合理利用 Spring Boot 的这些特性,能够让我们的项目更加健壮、高效。

随着技术的不断发展,Spring Boot 也在持续演进,未来我们可以期待它在性能优化、功能扩展等方面带来更多的惊喜。希望本文能为广大互联网软件开发人员在理解和使用 Spring Boot 3 的过程中提供有益的帮助,让我们一起在 Spring Boot 的技术海洋中不断探索前行。

最近发表
标签列表