spring boot的jar启动原理

进入spring boot 时代,java开发者们都熟知使用spring-boot-maven-plugin,可以将web项目打成jar包,然后java -jar 就可以执行,各位是否考虑过底层是怎么做的?类是如何加载的?以前为什么不是这么做的?
在了解具体细节之前,我们需要先了解一下不使用任何打包工具时,java程序时如何完成引用的,以及如何使用jdk默认的jar命令进行打包。

java程序加载jar包

在不使用任何工具的情况下,java程序加载jar包可以通过指定classpath的方式。

java -classpath <目录和 zip/jar 文件的类搜索路径>
                  用 : 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。

大家面试的时候一定遇到过类加载、双亲委派等问题。
类加载器从顶向下依次是:
BootStrapClassLoader->ExtClassLoader->AppClassLoader。
其中AppClassLoader作为默认类加载器,读取的就是classpath路径下的类文件。
我们不指定classpath时,默认会将 当前目录. 加入到classpath中。

使用 jar命令打jar包

首先我简单创建这样一个结构,其中App类内有main方法。
image.png
将项目编译一下,编译主类,依赖的类都会被编译。

javac com/yuvenhol/App.java

使用jar命令打jar包,注意这里需要使用-e命令,然后指定jar包入口。

jar -cvfe mytest.jar com.yuvenhol.App .      

我们可以解开jar包,看看里面都有什么。
image.png
可以看到除了源码、字节码和原数据(META-INF)。MANIFEST.MF内容如下。

Manifest-Version: 1.0
Created-By: 1.8.0_312 (Azul Systems, Inc.)
Main-Class: com.yuvenhol.App

这里Main-Class和打jar包时指定的入口一致。当我们使用java -jar 运行jar包时,读取MANIFEST.MF内容,读到正确的class。

spring boot程序的jar包的不同

以sentinel-dashboard.jar 为例,我们先看一个可运行的jar包里面都有什么。
image.png
首先看最重要的MANIFEST.MF 文件里面有什么内容。

Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Built-By: sczyh30
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Start-Class: com.alibaba.csp.sentinel.dashboard.DashboardApplication //应用程序的main方法
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.5.12
Created-By: Apache Maven 3.8.1
Build-Jdk: 1.8.0_152
Main-Class: org.springframework.boot.loader.JarLauncher //jar包启动的入口

需要注意的是,springboot 可运行jar包并非标准jar包,实际上是一个springboot特制的jar包。

我们可以看到里面描述了,jar包运行的入口(Main-Class)、springboot版本、lib所在的位置和lib目录等等信息,以及docker build所需的layers描述(这是一个boot2.3推出的功能,旨在减少docker iamge体积,具体细节可以看SpringBoot-2.3镜像方案为什么要做多个layer)。

为什么要搞一个JarLauncher 来作为启动类,而不直接使用我们定的main函数呢?

因为java规范默认是不支持嵌套jar包,在过去要实现类似的功能通常将多个jar包内的类提出来,再打到一个jar包内,这会带来很多冲突问题,并不好维护。而spring boot使用一个巧妙的方法绕过了这个限定,其中的奥秘就在arLauncher内。这是spring-boot-loader模块的内容,你可以直接下载源码了解,当然你只是想粗看一下也可以在github上看一下源码 link

代码写的比较复杂,抽象程度很高。我给大家简述一下,实际上就是在运行JarLauncher之后,根据BOOT-INF/classpath.idx内存储的jar包文件索引,加上我们的源码地址,组合成成文件资源列表被称为urls,使用urls作为参数创建了一个自定义的类加载器LaunchedURLClassLoader (和默认类加载器AppClassLoader一样extend URLClassLoader)。然后使用这个类加载器再去加载我们自己的main函数,需要类加载时会遍历urls去找是否有所需的class文件。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值