详细说明java -jar启动SpringBoot的jar包原理
我们知道SpringBoot的Jar文件可以使用java -jar xxx.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
比较一下:
我们对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加载运行的入口
JVM首先会调用该方法启动运行,该方法会调用其父类Launcher
的launch()
方法,launch()方法会先调用createClassLoader()
创建一个LaunchedURLClassLoader
的类加载器,该ClassLoader主要负责加载BOOT-INF/classes
下的应用程序编译后的class
文件和BOOT-INF/lib
下的应用程序依赖的第三方Jar包文件
并调用getMainClass()
方法获取Start-Class
配置信息,即应用程序启动类路径
然后会执行launch()重载方法,该方法将已创建好的类加载器设置到当前线程中,然后调用createMainMethodRunner()
方法创建MainMethodRunner
对象并将应用程序对应的启动类路径传给给该对象,并将该对象的实例返回
调用并执行MainMethodRunner
对象的run()方法,run()方法会通过mainClassName
属性(就是前面获取的Start-Class属性值)获取应用程序的启动类,最后通过反射的方式调用类中main方法,此时才开始运行应用类服务,到此我们的SpringBoot的Jar包终于启动完成启动了
- 本文标签: java SpringBoot
- 本文链接: https://www.58cto.cn/article/52
- 版权声明: 本文由程序言原创发布, 非商业性可自由转载、引用,但需署名作者且注明文章出处:程序言 》 详细说明java -jar启动SpringBoot的jar包原理 - https://www.58cto.cn/article/52