转载:从源码角度3分钟理解SpringBoot的jar可以直接运行的原因
在springboot项目中我们使用maven打包插件将项目打成一个jar之后,然后使用java -jar的命令就可以直接运行jar了,这是什么原理呢?今天来揭秘一下springboot的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> <plugins> <!-- spring-boot 打包 --> <plugin> <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方法中找到真正的应用启动类来执行。