从源码角度3分钟理解SpringBoot的jar可以直接运行的原因和原理
在springboot项目中我们使用maven打包插件将项目打成一个jar之后,然后使用java -jar的命令就可以直接运行jar了,这是什么原理呢?今天来揭秘一下 springbo ot的jar直接运行的原理。
1、制作jar
(1)添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
</dependency>
</dependencies>
<build>
<p>
<!-- spring-boot 打包 -->
<p>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
(2)编写基础的启动代码和测试类
------------------------启动类----------------------
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SpringJarApplication {
public static void main(String[] args) {
SpringApplication.run(SpringJarApplication.class, args);
}
}
------------------------测试类------------------------
@RestController
@RequestMapping("/test")
public class SpringJarController {
@GetMapping("/test01")
public String test01() {
return "test01";
}
}
------------------------配置文件------------------------
server:
port: 8080
spring:
application:
name: spring-jar
(3)使用springboot的插件打包
打包成功之后的日志输出:
到这里就完成使用springboot插件打包了一个jar。使用java -jar的命令运行的效果如下所示:
2、解析jar的结构
在本地的仓库中找到刚打的jar,然后通过工具打开springboot插件打包jar包,如下所示:
(1)BOOT-INF包
BOOT -INF包含应用程序的所有类文件和资源,在BOOT-INF包下的lib中将项目中需要依赖的jar都打包进来了,因此我们又称springboot通过插件打包的jar叫做fat jar。
(2)META-INF包
这个包下包含了一份很重要的清单文件,此文件包含了应用程序的元数据信息,如下是清单文件的详细信息:
Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Implementation-Title: spring.jar
Implementation-Version: 1.0-SNAPSHOT
Start-Class: com.longxia.jar.SpringJarApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.3.2.RELEASE
Created-By: Maven Jar Plugin 3.2.0
Main-Class: org.springframework.boot.loader.JarLauncher
我们需要重点关注的两处,一处是Main-Class,因为它指定了应用的主类,也就是jar包的入口位置;一处是Start-Class,它标识着项目的启动类位置。
3、jar的运行原理
在运行jar包的时候,首先会找到MANIFEST.MF下的JarLauncher类,此类的就是程序的入口,JarLauncher类的代码如下所示:
Fat jar在启动JarLauncher中的main函数的时候, Fat jar会负责创创建一个LunchedURLClassLoader来加载 BOOT -INF包下的lib中的jar,如下所示:
接下来在launch方法中寻找我们项目中的真正的启动类,那么如何寻着启动类呢?其实是文件清单中的Start-class中找,如下所示:
找到项目启动类之后,通过反射的方式启动我们的项目,于是乎我们可以看到经典的启动图标:
总结:
(1)springboot提供的打包插件可以将应用程序打包成一个可执行的fat jar,在fat jar中包含了项目所需要的依赖和springboot loader相关的类信息。
(2)当执行java -jar命令的时候会先去MAINFEST.MF这个清单文件中寻找jar的启动入口(也就是Main-Class中指定的JarLauncher),然后在JarLauncher类下的launch方法中找到真正的应用启动类来执行。