为什么springboot的jar包可以直接运行

72 阅读2分钟

Spring Boot 的 JAR 包可以直接运行的核心原理在于它采用了 可执行 JAR(Fat JAR)  技术,将应用代码、依赖库、嵌入式服务器(如 Tomcat、Jetty)以及资源文件整合到单个 JAR 文件中,并通过自定义的启动类实现自包含运行。以下是详细的原理剖析:

1. 可执行 JAR 的结构

Spring Boot 打包后的 JAR 文件包含以下关键部分:

plaintext

my-spring-boot-app.jar
├── META-INF/
│   └── MANIFEST.MF         # 清单文件,指定主类和启动配置
├── BOOT-INF/
│   ├── classes/            # 应用代码和资源
│   │   ├── com/
│   │   │   └── example/
│   │   │       └── MyApplication.class
│   │   └── application.properties
│   └── lib/                # 依赖的所有 JAR 包
│       ├── spring-boot.jar
│       ├── spring-core.jar
│       └── ...
└── org/                    # 嵌入式启动器类(如 org.springframework.boot.loader)

2. 核心启动机制

2.1 MANIFEST.MF 文件

可执行 JAR 的 MANIFEST.MF 中包含特殊配置:

manifest

Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.example.MyApplication
  • Main-Class:Spring Boot 自定义的启动类 JarLauncher,负责加载内部 JAR 和资源。
  • Start-Class:应用的主入口类(即包含 main 方法的类)。

2.2 自定义类加载器

Spring Boot 通过 LaunchedURLClassLoader 实现嵌套 JAR 的加载:

  1. 标准 JVM 限制:Java 原生类加载器无法直接加载嵌套在 JAR 中的 JAR(如 BOOT-INF/lib 下的依赖)。
  2. 自定义加载器突破限制LaunchedURLClassLoader 扩展了标准类加载器,能够从嵌套 JAR 中读取类和资源。

2.3 启动流程

  1. JVM 启动:执行 java -jar my-app.jar 时,JVM 首先加载 MANIFEST.MF 中指定的 Main-Class(即 JarLauncher)。
  2. 嵌套 JAR 加载JarLauncher 初始化 LaunchedURLClassLoader,将 BOOT-INF/lib 下的所有依赖添加到类路径中。
  3. 应用主类启动JarLauncher 反射调用 Start-Class(即 com.example.MyApplication)的 main 方法。
  4. Spring 上下文初始化main 方法触发 Spring Boot 应用的启动流程,包括自动配置、组件扫描和嵌入式服务器启动。

3. 嵌入式服务器的集成

Spring Boot 的嵌入式服务器(如 Tomcat)以依赖形式存在于 BOOT-INF/lib 中:

  1. 服务器作为普通依赖:Tomcat/Jetty 被打包到 JAR 中,作为应用的一部分运行。
  2. 自动配置:Spring Boot 自动配置嵌入式服务器,无需独立安装和配置。
  3. 内嵌运行:应用启动时,嵌入式服务器直接在 JVM 内初始化并监听端口,无需外部容器。

4. 总结

1.SpringBoot 提供了一个插件 spring-boot-maven-plugin 用于把程序打包成一个可执行的 jar 包。

2.Spring Boot 应用打包之后,生成一个 Fat jar (jar 包中包含 jar),包含了应用依赖的 jar 包和 Spring Boot loader 相关的类。

3.java -jar 会去找 jar 中的 manifest 文件,在那里面找到真正的启动类(Main-Class);

4.Fat jar 的启动 Main 函数是 JarLauncher,它负责创建一个 LaunchedURLClassLoader 来加载 boot-lib 下面的 jar,并以一个新线程启动应用的启动类的 Main 函数(找到 manifest 中的 Start-Class)。