java独立承担_springboot的jar为何能独立运行

能独立运行的jar文件

在开发springboot应用时,通过java -jar命令启动应用是常用的方式,今天就来一起了解这个简单操作背后的技术;

开发demo

开发一个springboot应用作为本次研究的对象,对应的版本信息如下:

JDK:1.8.0_211springboot:2.3.1.RELEASEmaven:3.6.0接下来开发springboot应用,这个应用异常简单:

springboot应用名为springbootstarterdemo,pom.xml文件内容:

eb572b9bb53c4d4319156fbacfe5ebbc.png

2. 只有一个java类,里面有个http接口:

22e61b22f64b509172afddd65510eb73.png

3. 编码完成,在pom.xml所在目录执行命令

mvn clean package -U -DskipTests

4. 构建成功后,在target目录下得到文件springbootstarterdemo-0.0.1-SNAPSHOT.jar

5. 就是这个springbootstarterdemo-0.0.1-SNAPSHOT.jar,此时执行java -jar springbootstarterdemo-0.0.1-SNAPSHOT.jar就能启动应用,如下图:

b96c4b6e4d711c7293414d46867f6e9e.png

接下来就用这个springbootstarterdemo-0.0.1-SNAPSHOT.jar来分析jar文件能够独立启动的原因;

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文件,在那里面找到真正的启动类;探查springbootstarterdemo-0.0.1-SNAPSHOT.jar

springbootstarterdemo-0.0.1-SNAPSHOT.jar是前面的springboot工程的构建结果,是个压缩包,用常见的压缩工具就能解压,我这里的环境是MacBook Pro,用unzip即可解压;解压后有很多内容,我们先关注manifest相关的,下图红框中就是manifest文件:

a5980b7f73567947044b36e11e18237a.png

3. 打开上图红框中的文件,内容如下:

d78434472b55b8ce6a55f64cd6d6fea9.png

4. 在上述内容可见Main-Class的值org.springframework.boot.loader.JarLauncher,这个和前面的java官方文档对应上了,正是这个JarLauncher类的代码中指定了真正的启动类;

疑惑出现

在MANIFEST.MF文件中有这么一行内容:Start-Class: com.bolingcavalry.springbootstarterdemo.Springbootstarter demoApplication

2. 前面的java官方文档中,只提到过Main-Class ,并没有提到Start-Class;

3. Start-Class的值是SpringbootstarterdemoApplication,这是我们的java代码中的唯一类,也只真正的应用启动类;

4. 所以问题就来了:理论上看,执行java -jar命令时JarLauncher类会被执行,但实际上是SpringbootstarterdemoApplication被执行了,这其中发生了什么呢?

猜测

动手之前先猜一下,个人觉得原因应该如下:

java -jar命令会启动JarLauncher;Start-Class是给JarLauncher用的;JarLauncher根据Start-Class找到了SpringbootstarterdemoApplication,然后执行它;分析JarLauncher

先下载SpringBoot源码,我下载的是2.3.1版本;JarLauncher所在的工程是spring-boot-loader,先弄明白JarLauncher的继承关系,如下图,可见JarLauncher继承自ExecutableArchiveLauncher,而ExecutableArchiveLauncher的父类Launcher位于最顶层,是个抽象类:

42348be017376cd8f9bba87d62580352.png

3. java -jar执行的是JarLauncher的main方法,如下,会实例化一个JarLauncher对象,然后执行其launch方法,并且将所有入参都带入:

publicstaticvoidmain(String[] args)throws Exception {new JarLauncher().launch(args);}

4. 上面的launch方法在父类Launcher中:

2268793be442fb4c1b7b2204ae388a9f.png

5. 可见要重点关注的是getMainClass()方法,在看这个方法之前,我们先去关注一个重要的成员变量archive,是JarLauncher的父类ExecutableArchiveLauncher的archive,如下可见,该变量又来自方法createArchive:

855f6f101a877d13d11ec49de9d66872.png

6. 方法来自Launcher.createArchive,如下所示,可见成员变量archive实际上是个JarFileArchive对象:

8c5da475ca0a7e874ea03b212233178f.png

7. 现在回到getMainClass()方法,可见his.archive.getManifest方法返回的是META-INF/MANIFEST.MF文件的内容,然后getValue(START_CLASS_ATTRIBUTE)方法实际上就是从META-INF/MANIFEST.MF中取得了Start-Class的属性:

d9d3901b68eb5fff2bdd0adf62a13763.png

8. 从上述分析可知:getMainClass()方法返回的是META-INF/MANIFEST.MF中取得了Start-Class的属性com.bolingcavalry.springbootstarterdemo.SpringbootstarterdemoApplication,再次回到launch方法中,可见最终运行的代码是launch(args, launchClass, classLoader),它的launchClass参数就是com.bolingcavalry.springbootstarterdemo.SpringbootstarterdemoApplication:

b3bca4f4dc5a7e618c8552af726ba2d8.png

9. 展开launch(args, launchClass, classLoader),最终查到了MainMethodRunner类:

7845e29dfbc4a6bc2e39579d564a9bd7.png

终于,真相大白了;

小结

最后尽可能简短做个小结,先看jar是如何产生的,如下图,maven插件生成的jar文件中,有常见的class、jar,也有符合java规范的MANIFEST.MF文件,并且,还在MANIFEST.MF文件中额外生成了名为Start-Class的配置,这里面是我们编写的应用启动类SpringbootstarterdemoApplication:

c088546873167c57bdc4f03316416410.png

启动类是JarLauncher,它是如何与MANIFEST.MF文件关联的呢?从下图可以看出,最终是通过JarFile类的成员变量manifestSupplier关联上的:

0b6f8a7c5c416160a6e4180e0dd669e2.png

再来看看关键代码的执行情况,如下图:

d2274c0d7892c5839e4bad18cd197c01.png

至此,SpringBoot的jar独立运行的基本原理已经清楚,探究的过程中,除了熟悉关键代码流程,还对jar中的文件有了更多了解,如果您正在学习SpringBoot,希望本文能给您一些参考;

官方文档

最后附上SpringBoot官方文档,可以看到Start-Class描述信息:

dd37a76eaba453e7419575dcca7f57e5.png

2. 上述文档明确提到:Start-Class定义的是实际的启动类,此时的您应该对一切都了然于胸,产生本该如此的感慨;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值