原创

详细说明java -jar启动SpringBoot的jar包原理

温馨提示:
本文最后更新于 2024年05月10日,已超过 257 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

我们知道SpringBoot的Jar文件可以使用java -jar xxx.jar命令来直接运行,但是不是所有的Jar包都可以直接运行呢?我们来找个一Jar包尝试一下看看会出现什么情况:
Jar运行
可以看到,这个Jar并不能运行,跑出了个错误,眼瞅着这个提示有点儿眼熟。首先当执行java -jar命令时JVM都干了些啥,接下来就简单分析一下:

当我们执行java -jar命令时,实际上启动了Java虚拟机(JVM),并告诉它去加载并执行我们在命令后面所指定的Jar文件,一般过程如下:

  • 解析命令行参数:首先JVM解析命令行中的参数,确定需要执行的Jar文件的路径
  • 加载Jar文件:JVM加载指定的Jar文件,该Jar文件通常包含了应用程序的所有代码、依赖库以及资源文件,因此也称为Fat Jar
  • 寻找主类:JVM在Jar文件的MANIFEST.MF文件中查找Main-Class属性,确定Jar文件的主类
    初始化类路径:JVM根据Jar文件的依赖关系,初始化类路径,确保所有需要的类库都可以被加载
  • 执行主类的main方法:JVM通过反射机制,调用应用类中的main方法,并传递命令行参数作为参数。应用程序的执行从这里开始

将普通的Jar和Fat Jar解压并打开他们的MANIFEST.MF比较一下:
MANIFEST.MF
我们对SpringBoot的Jar包MANIFEST.MF信息进行简单说明:

  • Manifest-Version:清单文件的版本号
  • Spring-Boot-Classpath-Index:Spring Boot 类路径索引文件的位置
  • Archiver-Version:打包工具版本信息
  • Built-By: 构建此 JAR 文件的人员或者工具
  • Start-Class:Spring Boot 应用程序的启动类,这是 Spring Boot 执行程序入口的类
  • Spring-Boot-Classes:Spring Boot 应用程序的类文件存放的目录
  • Spring-Boot-Lib:Spring Boot 应用程序的依赖库文件存放的目录
  • Spring-Boot-Version:Spring Boot 框架的版本信息
  • Created-By:创建此 JAR 文件的构建工具及版本信息
  • Build-Jdk:构建此 JAR 文件所使用的 JDK 版本
  • Main-Class:这是一个可执行 JAR 文件的入口类,负责启动 JAR 文件中的 Spring Boot 应用程序

可以看到普通的jar解压出来的MANIFEST.MF文件内并没有JVM需要的Main-Class等属性,也就是上述Jar运行的错误提示,JVM找不到要运行的入口。且该属性所指向的类也不是我们应用程序所开发的启动类,而是由SpringBoot定义的JarLauncher启动类,而我们应用的启动类则在Start-Class属性内配置

打包SpringBoot时我们要依赖SpringBoot提供了spring-boot-maven-plugin插件,它的主要功能就是用于把程序打包成前面我们所说的Fat Jar文件,并添加启动类JarLauncher,它负责创建一个LanuchedURLClassLoader来加载boot-lib下面的jar,并开启一个新线程启动应用的Main函数

在应用项目里引入下面的maven依赖就可以找到JarLauncher类来查看其具体执行过程:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-loader</artifactId>
</dependency>

打开JarLauncher类可以看到它有一个main()方法,这里就是JVM启动AppClassLoader加载运行的入口
JarLauncher.main()

JVM首先会调用该方法启动运行,该方法会调用其父类Launcherlaunch()方法,launch()方法会先调用createClassLoader()创建一个LaunchedURLClassLoader的类加载器,该ClassLoader主要负责加载BOOT-INF/classes下的应用程序编译后的class文件和BOOT-INF/lib下的应用程序依赖的第三方Jar包文件
Launcher.launch()

并调用getMainClass()方法获取Start-Class配置信息,即应用程序启动类路径
Start-Class

然后会执行launch()重载方法,该方法将已创建好的类加载器设置到当前线程中,然后调用createMainMethodRunner()方法创建MainMethodRunner对象并将应用程序对应的启动类路径传给给该对象,并将该对象的实例返回
MainMethodRunner

调用并执行MainMethodRunner对象的run()方法,run()方法会通过mainClassName属性(就是前面获取的Start-Class属性值)获取应用程序的启动类,最后通过反射的方式调用类中main方法,此时才开始运行应用类服务,到此我们的SpringBoot的Jar包终于启动完成启动了
MainMethodRunner.run()

正文到此结束
本文目录