为什么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 为例:

  1. 执行命令:
    java -jar demo-0.0.1-SNAPSHOT.jar
  2. JarLauncher 初始化:
    • 解析 JAR 结构,识别 BOOT-INF/classes(应用代码)和 BOOT-INF/lib(依赖库)。
    • 创建 LaunchedURLClassLoader,动态构建类路径。
  3. 启动 Spring 应用:
    • 反射调用 Start-Class(如 com.example.DemoApplication)的 main() 方法。
    • 执行 SpringApplication.run(),触发自动配置(如根据 spring-boot-starter-web 自动配置 Tomcat)。
  4. 嵌入式容器启动:
    • Tomcat 监听指定端口(默认 8080),加载 Spring MVC 控制器。
    • 应用可响应 HTTP 请求(如访问 http://localhost:8080/api)。

⚠️ 四、常见问题与解决

  1. 依赖冲突

    • 现象
      NoSuchMethodError 或 ClassNotFoundException
    • 解决
      通过 mvn dependency:tree 检查依赖树,排除冲突库。
  2. 端口占用

    • 解决
      运行时指定端口:
      java -jar app.jar --server.port=8081
  3. 配置文件未加载

    • 原因
      application.yml 未放入 BOOT-INF/classes
    • 解决
      确保配置文件位于 src/main/resources(打包后自动进入 BOOT-INF/classes)。

💎 总结

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

  1. 一体化打包
    依赖、应用代码、嵌入式容器合一,简化部署。
  2. 智能启动器
    JarLauncher 动态构建类路径,无缝衔接 Spring 启动流程。
  3. 类加载优化
    打破双亲委派,优先加载项目本地类。

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

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

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。