为什么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
点赞
收藏
关注作者