1-SpringBoot启动详解,loader机制详细分析

本文探讨SpringBoot为何能直接运行jar包,解析其内部结构和启动原理。SpringBoot通过特殊打包方式,使jar内包含启动类与其他依赖,符合Java的jar协议。JarLauncher是启动核心,通过定制类加载器加载用户定义的入口类,实现免容器运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


我准备战斗到最后,不是因为我勇敢,是我想见证一切。 --双雪涛《猎人》


Thinking

  1. 一个技术,为什么要用它,解决了那些问题?
  2. 如果不用会怎么样,有没有其它的解决方法?
  3. 对比其它的解决方案,为什么最终选择了这种,都有何利弊?
  4. 你觉得项目中还有那些地方可以用到,如果用了会带来那些问题?
  5. 这些问题你又如何去解决的呢?

声明:本文基于springboot 2.1.3.RELEASE

正文的第一个疑问就是:

  1. springboot 为什么可以直接使用jar 运行?
  2. 那么jar包的内部解构是怎么样的?
  3. springboot 的启动过程又是怎么样的?

这里首先声明在java的归档文件中(jar)的规定:

​ 在一个jar文件当中,我们必须要将指定为Main-Class的那个类作为顶层的jar文件(就是该启动类的jar文件必须放置在整个解压目录或者jar文件内部的顶层目录下),意思就是,执行的Main-Class是不允许被嵌套的。

​ 对于一个Jar文件来说,被指定为入口类Main-Class的一个具体类,那么这个类连同他的包结构,一定是位于这个Jar文件的顶层目录,而不能再位于其他的子目录中。

  • 以上两种说法,强调了SpringBoot就存在了问题,在一个打包完jar文件后,只能允许一个Main-Class入口类,可是我们自己写的启动类是根本不具备启动整个项目的实力的,那么SpringBoot是怎么完美的避开这种协议,实现jar包中嵌套用户启动类,并且可以完美随处运行的呢?

1、SpringBoot jar包的内部结构

​ 将打包好的Jar包,使用命令解压出来

image-20200524174620780

image-20200524174940413

  1. 存放的是 配置文件和编写的字节码文件
  2. 存放的是自动生成的一些配置信息(类似于:maven配置,jdk环境、os环境等) you should not put anything into META-INF yourself. Instead
  3. 存放的是真正的springboot 的启动文件的字节码文件
    1. image-20200524175422956
    2. 大致可以看到在该启动类下的路径,尝试使用该路径引入jar依赖
        <!--引入 springboot 启动依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-loader</artifactId>
        </dependency>

引入该jar后,可以简单的发现,该jar包的所有路径都是跟解压出来的jar的loader路径下的内容相同的。

image-20200524180459535

不难发现了,speingboot正是使用的spring-boot-loader这个jar来完成springboot 的整个启动加载动作的。

在源码面前,所有的花哨都是扯淡的😄,来🐱一眼里面最显眼的JarLauncher类。

image-20200524180811303

是不是一眼就感觉到亲切无比了哈?😄

这里声明一点,我们引入的spring-boot-loader是不会影响springboot 的启动的。但是会在加载的lib目录下生成jar文件,我们重新打包一次,🐱一眼。

image-20200524181433685

其他目录并没有什么改变。

至此,大概的了解了,springboot 打包为jar后的整个目录样子。

下面,探讨一下这种路径的优点,或者说为什么是这样的结构

2、SpringBoot-启动原理

2.1、为什么SpringBoot打包的jar可以直接运行

当执行java -jar spring_lecture-0.0.1.jar命令时,整个jar的入口是什么?

​ 在上面简单的查看了一下整个jar包的目录结构,在Java运行jar时,是根据MATA-INF中的.MF文件,寻找到Main-Class指定的全限定名进行加载的。

<jar ...>
    <manifest>
        <attribute name="Main-Class" value="MyApplication"/>
    </manifest>
</jar>

​ 所以,在jar文件中,MATA-INF中的.MF文件定义了启动类

<think>嗯,用户让我分析Spring Boot的JAR文件中每个文件的作用。首先,我需要回想一下Spring Boot项目打包后的结构。记得标准的Spring Boot可执行JAR采用的是“fat jar”形式,也就是包含所有依赖的单一JAR包。不过,用户可能对这个结构不太清楚,我需要详细解释。 首先,得确认用户可能的使用场景。他们可能是刚接触Spring Boot的开发者,或者对打包机制不太熟悉,想了解内部结构以便排查问题,或者进行自定义配置。所以,我需要用简单明了的语言,分层次说明每个文件和目录的作用。 接下来,我需要分解JAR文件的组成部分。通常,解压后的根目录会有META-INF、BOOT-INF、org这样的目录。每个目录下有不同的文件,比如MANIFEST.MF、Spring Boot的类加载器相关文件,以及应用本身的代码和依赖库。 要确保每个部分都解释到位。例如,META-INF下的MANIFEST.MF文件是JAR的清单文件,里面指定了主类等信息,这对启动至关重要。而BOOT-INF里又分为classes和lib,前者是应用自己的代码,后者是依赖的JAR包。还有org/springframework/boot/loader下的类,负责加载这些嵌套的JAR,这部分需要详细说明,因为用户可能对类加载机制不熟悉。 另外,用户可能想知道这些结构如何协同工作,比如启动过程是怎样的,类加载器如何加载依赖。这时候需要简要说明Spring Boot的Launcher机制,比如JarLauncher类的作用。 同时,用户可能有疑问,如何查看这些文件,可能需要指导他们使用jar命令解压或者直接查看。不过用户的问题主要在于分析文件作用,这部分可能不需要详细步骤,但如果有用户后续提问,可以补充。 还要注意避免技术术语过于复杂,用通俗易懂的语言解释。比如,解释BOOT-INF/classes时,可以说明这是存放编译后的Java类文件、配置文件的位置,用户的应用代码就在这里。 最后,可能需要总结一下整个结构如何支持可执行JAR的运行,强调Spring Boot的独特设计,比如嵌套JAR和自定义类加载器,这样用户能有一个整体的理解。 检查是否有遗漏的部分,比如是否有其他可能的文件或目录需要说明,确保覆盖所有主要部分。同时,提醒用户如果需要进一步了解某个部分,可以深入探讨,保持回答的开放性。</think>以下是Spring Boot可执行JAR文件的标准结构分析(解压后): ``` ├── META-INF/ │ ├── MANIFEST.MF # 核心启动配置清单 │ └── maven/ # Maven项目元数据(可选) ├── BOOT-INF/ │ ├── classes/ # 应用核心资源 │ │ ├── static/ # 静态资源(HTML/CSS/JS等) │ │ ├── templates/ # 模板文件(Thymeleaf等) │ │ ├── application.yml # 配置文件 │ │ └── 你的Java类文件 # 编译后的.class文件 │ └── lib/ # 依赖库集合 │ └── *.jar # 所有第三方依赖JAR文件 └── org/ └── springframework/ └── boot/ └── loader/ # Spring Boot启动器 ├── JarLauncher.class # 入口启动类 └── ... # 其他类加载器相关实现 ``` 关键文件详解1. **META-INF/MANIFEST.MF** ```properties Main-Class: org.springframework.boot.loader.JarLauncher # 指定启动入口 Start-Class: com.example.Application # 你的主程序类 Spring-Boot-Version: 3.1.5 # Spring Boot版本 Spring-Boot-Classes: BOOT-INF/classes/ # 类文件路径 Spring-Boot-Lib: BOOT-INF/lib/ # 依赖库路径 ``` 2. **BOOT-INF目录** - `classes/`:包含编译后的.class文件、application.properties/yml、静态资源和模板文件 - `lib/`:存放所有依赖的第三方库(包含Spring框架自身的JAR) 3. **org/springframework/boot/loader** - 包含Spring Boot独创的类加载器实现(如JarLauncher) - 负责加载嵌套JAR文件(BOOT-INF/lib下的依赖) - 实现嵌入式Tomcat/Jetty服务器的资源加载 运行原理: 1. 执行`java -jar`时,JVM根据MANIFEST.MF找到JarLauncher 2. JarLauncher创建特殊类加载器,加载BOOT-INF下的资源 3. 最终启动Start-Class指定的用户主程序 查看方法: ```bash # 解压查看结构 jar xvf your-app.jar # 或直接列出内容 jar tvf your-app.jar ``` 这种分层结构的设计优势: - 单文件部署:所有依赖自包含 - 依赖隔离:避免与外部类路径冲突 - 快速启动:优化类加载机制 - 支持嵌套JAR加载(常规JVM无法直接加载嵌套JAR) 如果需要分析具体项目中的JAR内容,建议使用JD-GUI等反编译工具查看类文件,或直接解压检查资源配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值