SpringBoot 是如何通过jar包启动的

SpringBoot 是如何通过jar包启动的

得益于SpringBoot的封装,我们可以只通过jar -jar一行命令便启动一个web项目。再也不用操心搭建tomcat等相关web 容器。那么,你是否探究过SpringBoot是如何达到这一操作的呢?只有了解了底层实现原理,才能更好的掌握该项技术 带来的好处以及性能调优。本篇文章带大家聊一探究竟。

java -jar做了什么

​ 先要弄清楚java -jar命令做了什么,在oracle官网找到了该命令的描述:

If the -jar option is specified, its argument is the name of the JAR file containing class and resource files for the application. The startup
class must be indicated by the Main-Class manifest header in its source code.

再次秀出我蹩脚的英文翻译:

使用-jar参数时,后面的参数是的jar文件名(本例中是springbootstarterdemo-0.0.1-SNAPSHOT.jar);

该jar文件中包含的是class和资源文件;

在manifest文件中有Main-Class的定义;

Main-Class的源码中指定了整个应用的启动类;(in its source code)

总结:java -jar会去找jar中的manifest文件,在那里面找到真正的启动类;

MANIFEST.MF文件分析

Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Implementation-Title: Demo
Implementation-Version: 1.0-SNAPSHOT
Start-Class: com.example.DemoApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.3.3.RELEASE
Created-By: Maven Jar Plugin 3.2.0
Main-Class: org.springframework.boot.loader.JarLauncher

理论上看,执行java -jar命令时JarLauncher类会被执行,但实际上是com.tulingxueyuan.Application被执行了,这其 中发生了什么呢?为什么要这么做呢?

  • Java没有提供任何标准的方式来加载嵌套的jar文件(即,它们本身包含在jar中的jar文件)。

Spring Boot项目的pom.xml文件中默认使用如下插件进行打包:


 	
 		
 			org.springframework.boot
			spring‐boot‐maven‐plugin
		
	

spring-boot-maven-plugin项目存在于spring-boot-tools目录中。

spring-boot-maven-plugin默认有5个goals: repackage、run、start、stop、build-info。

在打包的时候默认使用的是repackage。

spring-boot-maven-plugin的repackage能够将mvn package生成的软件包,再次打包为可执行的软件包,并将mvn package生成的软件包重命名为*.original。

spring-boot-maven-plugin的repackage在代码层面调用了RepackageMojo的execute方法,而在该方法中又调用了 repackage方法。

从MANIFEST.MF可以看到Main函数是JarLauncher,下面来分析它的工作流程。JarLauncher类的继承结构是

 class JarLauncher extends ExecutableArchiveLauncher
 class ExecutableArchiveLauncher extends Launcher

按照定义,JarLauncher可以加载内部/BOOT-INF/lib下的jar及/BOOT-INF/classes下的应用class,其实JarLauncher实 现很简单:

 public class JarLauncher extends ExecutableArchiveLauncher {
 	public JarLauncher() {}
 	
 	public static void main(String[] args) throws Exception {
		 new JarLauncher().launch(args);
 	}
 }

其 主 入 口 新 建 了 JarLauncher 并 调 用 父 类 Launcher 中 的 launch 方 法 启 动 程 序 。 在 创 建 JarLauncher 时 , 父 类 ExecutableArchiveLauncher找到自己所在的jar,并创建archive。

JarLauncher继承于org.springframework.boot.loader.ExecutableArchiveLauncher。该类的无参构造方法最主要的功 能就是构建了当前main方法所在的FatJar的JarFileArchive对象。下面来看launch方法。该方法主要是做了2个事情:

(1)以FatJar为file作为入参,构造JarFileArchive对象。获取其中所有的资源目标,取得其Url,将这些URL作为参数, 构建了一个URLClassLoader。

(2)以第一步构建的ClassLoader加载MANIFEST.MF文件中Start-Class指向的业务类,并且执行静态方法main。进而启动整个程序。

在Launcher的launch方法中,通过以上archive的getNestedArchives方法找到/BOOT-INF/lib下所有jar及/BOOTINF/classes目录所对应的archive,通过这些archives的url生成LaunchedURLClassLoader,并将其设置为线程上下文类加载器,启动应用。

至此,再执行我们应用程序主入口类的main方法,所有应用程序类文件均可通过/BOOT-INF/classes加载,所有依赖的 第三方jar均可通过/BOOT-INF/lib加载。

Spring Boot的Jar应用启动流程总结

(1)Spring Boot应用打包之后,生成一个Fat jar,包含了应用依赖的jar包和Spring Boot loader相关的类。

(2)Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载/lib下面的jar,并以一 个新线程启动应用的Main函数。

你可能感兴趣的:(jar,spring,boot,java)