为什么Spring boot的 jar 可以直接运行?

为什么Spring boot的 jar 可以直接运行?

为什么Spring boot的 jar 可以直接运行?

举报

一颗小谷粒

发表于 2025/07/31 19:02:26

2025/07/31

【摘要】 为什么Spring boot的 jar 可以直接运行?Spring Boot 的可执行 JAR(即“Fat JAR”)能够直接通过 java -jar 命令运行,其核心在于独特的结构设计、自定义启动器和类加载机制。以下从原理和案例角度详细分析:⚙️ 一、可执行JAR的核心原理1. 特殊结构设计Spring Boot Fat JAR 的结构与传统 JAR 不同,包含以下关键目录:BOOT-IN...

为什么Spring boot的 jar 可以直接运行?

Spring Boot 的可执行 JAR(即“Fat JAR”)能够直接通过 java -jar 命令运行,其核心在于独特的结构设计、自定义启动器和类加载机制。以下从原理和案例角度详细分析:

⚙️ 一、可执行JAR的核心原理

1. 特殊结构设计

Spring Boot Fat JAR 的结构与传统 JAR 不同,包含以下关键目录:

BOOT-INF/classes

存放项目编译后的类文件(如 *.class 和配置文件)。

BOOT-INF/lib

包含所有第三方依赖库(如 Spring、Tomcat 等)。

META-INF/MANIFEST.MF

定义启动入口(Main-Class: org.springframework.boot.loader.JarLauncher)和启动类(Start-Class: com.example.MainApplication)。

org/springframework/boot/loader

存放 Spring Boot 的启动器类(如 JarLauncher)。

2. 启动流程:JarLauncher 的作用

当执行 java -jar app.jar 时:

JVM 读取 MANIFEST.MF 中的 Main-Class,加载 JarLauncher。

JarLauncher

创建 LaunchedURLClassLoader(自定义类加载器),将 BOOT-INF/classes 和 BOOT-INF/lib/*.jar 加入类路径。

通过反射调用 MANIFEST.MF 中定义的 Start-Class(即用户的主启动类),启动 Spring 应用。

3. 类加载机制突破双亲委派

传统 JAR 依赖外部类路径,而 Spring Boot 的 LaunchedURLClassLoader 打破了双亲委派模型:

优先从 BOOT-INF/classes 和 BOOT-INF/lib 加载类,避免依赖冲突(如不同版本的 JSON 库)。

若未找到,再委托父类加载器(如 AppClassLoader)加载 JDK 核心类。

4. 嵌入式容器集成

Fat JAR 内置了 Tomcat、Jetty 等 Servlet 容器:

依赖库(如 spring-boot-starter-web)已包含嵌入式容器。

启动时自动初始化容器并部署应用,无需外部 Web 服务器。

🆚 二、与传统JAR的对比

特性

传统JAR

Spring Boot Fat JAR

依赖管理

依赖外置,需手动配置类路径

所有依赖打包到 BOOT-INF/lib

启动方式

需指定主类和类路径(复杂)

直接 java -jar 运行

容器依赖

需外部 Servlet 容器(如 Tomcat)

内置嵌入式容器

类加载

遵循双亲委派,易冲突

自定义加载器优先加载项目类,避免冲突

💻 三、案例分析:启动流程分解

以典型 Spring Boot 应用 demo-0.0.1-SNAPSHOT.jar 为例:

执行命令:

java -jar demo-0.0.1-SNAPSHOT.jar

JarLauncher 初始化:

解析 JAR 结构,识别 BOOT-INF/classes(应用代码)和 BOOT-INF/lib(依赖库)。

创建 LaunchedURLClassLoader,动态构建类路径。

启动 Spring 应用:

反射调用 Start-Class(如 com.example.DemoApplication)的 main() 方法。

执行 SpringApplication.run(),触发自动配置(如根据 spring-boot-starter-web 自动配置 Tomcat)。

嵌入式容器启动:

Tomcat 监听指定端口(默认 8080),加载 Spring MVC 控制器。

应用可响应 HTTP 请求(如访问 http://localhost:8080/api)。

⚠️ 四、常见问题与解决

依赖冲突:

现象

NoSuchMethodError 或 ClassNotFoundException。

解决

通过 mvn dependency:tree 检查依赖树,排除冲突库。

端口占用:

解决

运行时指定端口:

java -jar app.jar --server.port=8081

配置文件未加载:

原因

application.yml 未放入 BOOT-INF/classes。

解决

确保配置文件位于 src/main/resources(打包后自动进入 BOOT-INF/classes)。

💎 总结

Spring Boot 可执行 JAR 的核心创新在于:

一体化打包

依赖、应用代码、嵌入式容器合一,简化部署。

智能启动器

JarLauncher 动态构建类路径,无缝衔接 Spring 启动流程。

类加载优化

打破双亲委派,优先加载项目本地类。

这种设计使 Spring Boot 应用成为“开箱即用”的独立单元,完美适配云原生和微服务架构。开发者只需关注业务逻辑,无需操心环境配置,极大提升了开发和部署效率。

推荐

华为开发者空间发布

让每位开发者拥有一台云主机

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:

cloudbbs@huaweicloud.com

Spring

Tomcat

点赞

收藏

关注作者

相关推荐

为什么PDF转成Word后是图片,怎么才能修改?
丹麦2018世界杯成绩单(丹麦队2018世界杯成绩)
三星s7edge充电器多少w(三星s7无线充电多少w)
阴阳师饭团怎么获得 京都决战饭团体力恢复时间是多久

本文标签