Spring Boot 打包成Jar包运行原理分析
SpringBoot打包
相比与传统的Java打包方式,使用SpringBoot打包插件打包成jar包后,可以直接使用java -jar
运行SpringBoot项目,本篇就来分析一下运行的原理。
SpringBoot打包插件
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>
打包完后会生成两个文件,一个***.jar
和***.jar.original
.jar
文件是SpringBoot打包后生成的文件,.jar.original
是用原生方式打包生成的文件,对比一下两个的区别
.jar.original文件
.jar文件
.jar.original
就是普通的jar打包的结构,这里主要看.jar
文件的结构:
META-INFO目录:META-INFO/MANIFEST.MF里包含了jar包的元数据,包含了项目的启动类等信息.
org目录:该目录下包含的是启动项目的一些类,启动的过程就在这个包里。
BOOT-INFO目录:本地项目的代码(BOOT-INF/classes),以及所需的以依赖(BOOT-INFO/lib)
重点 META-INFO/MANIFEST.MF
Manifest-Version: 1.0 Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Implementation-Title: demo Implementation-Version: 0.0.1-SNAPSHOT Spring-Boot-Layers-Index: BOOT-INF/layers.idx Start-Class: com.example.demo.DemoApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Build-Jdk-Spec: 1.8 Spring-Boot-Version: 2.4.5 Created-By: Maven Jar Plugin 3.2.0 Main-Class: org.springframework.boot.loader.JarLauncher
这里有几个重点的字段
- Main-Class :jar包启动类,这是java规定的字段,存在这个字段的情况下, 在
java -jar
时,jar包才会运行起来 - Start-Class:本地项目的启动类
- Spring-Boot-Classes:加载应用类的入口
- Spring-Boot-Lib:项目所需的依赖
有了Main-Class启动类,那就直接进入到JarLauncher
里查看运行的过程
public static void main(String[] args) throws Exception { (new JarLauncher()).launch(args); }
在JarLauncher
的main
方法里调用了launch
方法,launch
方法的具体实现在JarLauncher
的抽象父类Launcher
中实现
protected void launch(String[] args) throws Exception { if (!this.isExploded()) { JarFile.registerUrlProtocolHandler(); } ClassLoader classLoader = this.createClassLoader(this.getClassPathArchivesIterator()); String jarMode = System.getProperty("jarmode"); String launchClass = jarMode != null && !jarMode.isEmpty() ? "org.springframework.boot.loader.jarmode.JarModeLauncher" : this.getMainClass(); this.launch(args, launchClass, classLoader); }
首先获取了类加载器。
然后获取jarMode,再根据jarMode获取launchClass,如果没有设置jarMode,则根据getMainClass
方法获取,getMainClass
的具体实现在ExecutableArchiveLauncher
中实现
protected String getMainClass() throws Exception { Manifest manifest = this.archive.getManifest(); String mainClass = null; if (manifest != null) { mainClass = manifest.getMainAttributes().getValue("Start-Class"); } if (mainClass == null) { throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this); } else { return mainClass; } }
在getMainClass
里获取了MANIFEST.MF
文件里Start-Class
字段的值,也就是本地项目的启动类。
最后调用this.launch(args, launchClass, classLoader);
protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception { Thread.currentThread().setContextClassLoader(classLoader); this.createMainMethodRunner(launchClass, args, classLoader).run(); }
调用MainMethodRunner
的run()
方法
public void run() throws Exception { Class<?> mainClass = Class.forName(this.mainClassName, false, Thread.currentThread().getContextClassLoader()); Method mainMethod = mainClass.getDeclaredMethod("main", String[].class); mainMethod.setAccessible(true); mainMethod.invoke((Object)null, this.args); }
在run()
方法里通过反射拿到了项目的启动类的main
方法,从而启动本地项目。
以上就是Spring Boot 打包成Jar包运行的原理的详细内容,更多关于Spring Boot Jar包的资料请关注脚本之家其它相关文章!
相关文章
Springboot集成Spring Security实现JWT认证的步骤详解
这篇文章主要介绍了Springboot集成Spring Security实现JWT认证的步骤详解,帮助大家更好的理解和使用springboot,感兴趣的朋友可以了解下2021-02-02
最新评论