java -jar xx.jar是如何运行的
文章目录
- 前言
- 一、jar包是什么?
- 二、他们的区别
- 1.功能目的
- 2.文件目录
- 相同点:
- 不同点:
- 3.运行原理
- 1.springboot的入口
- 2.Springbootloader作用
- 总结
- 额外补充
- Java → JVM → glibc → 内核 [JVM启动过程源码流程分析](https://blog.csdn.net/u014106644/article/details/89428482)
前言
刚学java时,我们还都不会用ide,那会我们都直接使用javac编译,java来运行;但都是针对单个文件;这个是容易理解的;可当一个完整项目的springboot 的jar包通过java -jar 后是如何运行的呢?
一、jar包是什么?
首先我们要知道java是不支持jar包中内嵌jar包的读取的;所以像springboot打包好的jar包,里面是有lib文件夹,里面全是*.jar。这种情况单靠java是不可能读取里面的class文件的。
对于jar文件,我们首先要明白它实际上是哟有两种情况的:
- 一种就是咱们经常能看到的,通过springboot打包好的可运行jar,这是一种;
- 还有一种就是我们缺少思考没有想过,但却能看到的,就是我们开发引用的jar包,也就是springboot打包好的jar包中的lib文件夹下的jar包,这些jar包,或者说依赖,也都是一个个单独的jar包;
二、他们的区别
1.功能目的
虽然都是以.jar结尾,但功能不同:一个是可运行的jar,目的就是为了可以单独运行;一个是作为依赖的jar(它是不能单独运行的,即使它有内置tomcat也不行的),目的就是被别人引用;
2.文件目录
下图是一个可运行jar的内部目录结构和一个依赖jar的内部结构
图1 这是一个简单Springboot项目的目录结构 | 图2 这是logback-classic-1.2.10.jar的目录结构 |
这个只是给出了目录结构,具体不同,大家可以自己找两个jar包仔细对比的看下。这里只说结论:
相同点:
1.META-INF目录下都有maven目录,这个目录里面放着pom.xml的配置文件;
2.META-INF目录下都有MANIFEST.MF。
不同点:
1.BOOT-INF是可运行jar包才有的,里面classes目录是咱们写的代码的classs文件,另一个lib就是其他依赖jar包的位置;
2.普通的依赖jar包,则是直接将业务放到与META-INF同级的目录中。
3.可运行jar的META-INF下无services目录,普通jar有
4.都有的org目录,但里面东西却不同。
3.运行原理
我们知道tomcat在没有项目的情况下也是能独立启动的,java一样,即使没有jar包运行,单独也是可运行的,就是我们的jvm。jvm的启动加载运行jvm类加载机制与过程,这里就不再赘述了。
1.springboot的入口
还记得上面的MANIFEST.MF文件吗
这个就是springboot的入口,而这个文件的位置就是根目录org下,这个目录是在咱项目打jar包的时候就生成了的。spring-boot-loader是SpringBoot的引导程序,当你使用Maven-Install打包一个SpringBoot单一JAR包时,SpringBootLoader的代码被拷贝到JAR中。(即这个org目录)
SpringBootLoader读取内嵌JAR资源的关键(内嵌JAR以STORED模式存储)(即:非压缩,另一个模式是:DEFLATED)
2.Springbootloader作用
我们看到,SpringBootLoader:
- 接管了SpringBoot程序的启动入口(Main-Class)
- 对JDK中java.util.zip.ZipFile实现了扩展,以便支持内嵌JAR中class的随机访问
3.提供了SpringBoot-ClassLoader负责BOOT-INF下classes、lib的资源加载(Spring-Boot-Classes、Spring-Boot-Lib内容构成了应用真正的class-path)
通俗来讲就是,我们开发认为的主方法,并不是程序运行真正的主方法,它的前面还有JarLauncher;
4.是JarLauncher最终通过JarFile类的成员变量manifestSupplier关联上的:
5.jvm如何识别MANIFEST.MF文件的Main-Class?
在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.MF文件的Main-Class,在那里面找到真正的启动类;
总结
所以,从jvm到springboot,实际流程如下。
操作系统底层c/c++启动jre --> 找到MANIFEST.MF文件通过JarLauncher --> Application.java的main方法
额外补充
上面主要讲了springboot的主类是如何被java找到的,但jvm是如何找到JarLauncher的呢?
下面是我找的一个解释:
1.首先main方法执行需要一个操作来启动,像java Mm这种命令
2.这种命令首先是操作系统解析找到java命令属于jdk的东西,并调用jdk的的启动函数, 就像windows的双击操作一样,双击肯定是操作系统搞了什么小动作打开了软件
3.当操作系统调用了虚拟机的命令后,虚拟机会拿到命令的参数比如 Mm,然后去找编译后的文件
4.虚拟机找到文件后会调用jdk中的java代码,找到这个类sun.launcher.LauncherHelper,这个类作为一个工具类,作为桥梁链接了c++和java代码
5.调用sun.launcher.LauncherHelper类的checkAndLoadMain方法,通过这个方法找执行类Mm的Main方法
6.加载好之后执行Main
这是另一个解释:
在JavaMain()函数(定义在openjdk/jdk/src/share/bin/java.c文件中)中调用LoadMainClass()函数加载Java主类。
我们先看下LoadMainClass的细节,看看她咋加载的。通过GetLauncherHelperClass方法,我们终于看到了熟悉的身影:sun/launcher/LauncherHelper
LoadMainClass做了三件事:
1、获取LauncherHelper实例
2、通过checkAndLoadMain方法使用ClassLoader.getSystemClassLoader初始化org.springframework.boot.loader.JarLauncher class
3、makePlatformString获取utf-8后的string
下面附上这个类的截图
在jvm核心包rt.jar中。
Java 离 Linux 内核到底有多远?
第 1 步,调用 InitializeJVM 初始化 JVM。InitializeJVM 会调用 ifn->CreateJavaVM,也就是libjvm.so 中的 JNI_CreateJavaVM。
第 2 步,LoadMainClass,最终调用的是 JVM_FindClassFromBootLoader,也是通过动态链接找到函数(定义在 hotspot/share/prims/ 下),然后调用它。
第 3 和第 4 步,Java 的同学应该知道,这就是调用 main 函数。
加载主类LoadMainClass
LoadMainClass执行过程,主要是利用JNI方法来获取主类名称,进行类名处理,以及加载主类。
LauncherHelper你的祖坟终于找到了!!!
Java → JVM → glibc → 内核
JVM启动过程源码流程分析
java -jar xx.jar是如何运行的相关推荐
- java 启动方式 java -jar xx.jar
1.窗口被锁定,可按CTRL + C打断程序运行,关闭窗口程序停止运行 java -jar XXX.jar 2.窗口不被锁定,关闭窗口时,程序停止运行 java -jar XXX.jar & ...
- java -jar xx.jar 时报错:Exception in thread main java.lang.UnsupportedClassVersionError:
在linux服务器上运行java -jar xxx.jar 时报错 :Exception in thread "main" java.lang.UnsupportedClassVe ...
- java jar 最大内存大小_Java运行Jar包内存配置的操作
Java运行Jar包内存配置的操作,内存,大小,空间,最小,这是 Java运行Jar包内存配置的操作 易采站长站,站长之家为您整理了Java运行Jar包内存配置的操作的相关内容. 如下: java - ...
- maven install后,java -jar XXXX.jar运行---找不到主类问题 以及 虚拟机中执行jar包后 访问页面出现Java heap space等其他问题
这是前几天遇到的问题了,当天晚上想写下来来着,后来有事情就一直搁置到现在了. 由于我想将SpringCloud项目都导出jar包在虚拟机上运行,然后本地访问,所以先将SpringCloud中的注册中心 ...
- 将Java程序打jar包并运行
1)接着上篇博客继续说手动编译之后,将代码打成jar包,然后直接"java -jar lz.jar"运行不成功的问题.还是先上代码: 这个是Demo类: package org.l ...
- Eclipse中将java类打成jar包形式运行
记录一次帮助小伙伴将java类打成jar包运行 1.创建java project项目 file > new > project > java project 随便起一个项目名称,fi ...
- linux java jar打包_【Java】Java程序打包成jar包在Linux上运行
当需要把在Windows上开发的Java程序用在Linux上运行时,就需要吧该Java程序打包成jar包上传到Linux上去运行. 1.Java程序用MyEclipse打包成可运行的jar包 (1)在 ...
- java生成cmd jar包_Java程序运行机制及cmd编译运行探究(二) cmd编译运行Java程序并打成jar包...
目标:写一个RandomUtils.java工具类,返回一个随机数,并把这个类的字节码文件打成jar包 在Java运行机制及cmd编译运行探究(一)准备工作一文中,我总结了一部分要用到的cmd及编译运 ...
- java jar 启动项目,SpringBoot项目运行jar包启动的步骤流程解析
SpringBoot项目在开发中,方便快捷,有一点原因就是SpringBoot项目可以打jar包运行:把jar包直接扔服务器上,然后运行jar包就能访问项目接口了.下面介绍SpringBoot项目打j ...
最新文章
- ionic开发中页面跳转隐藏底部Ttab
- python相关概念
- 从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(三)
- Common Knowledge_快速幂
- (转载)控制反转(IoC)与依赖注入(DI)
- 任务不再等待!玩转DataWorks资源组
- shell echo 彩色字体
- numpy库学习总结
- 喜马拉雅下载成mp3方法
- qq音乐主页 思路解析(及代码)
- WRF/CMAQ 安装教程
- 用Angular实现图片上传问题
- git core.autocrlf配置说明
- pytest框架中setup、teardown和setup_class、teardown_class
- 魔数湖南大学程序设计作业
- 微信公众号获取关注页面链接
- 申论(基础题)之基础题型梳理
- 制作apt-get本地源解决无网络情况下安装软件
- Auto.js实例京东领金豆
- 支持多商家在线客服系统源码
热门文章
- SpringCloud系列之服务注册中心(Eureka)
- TTL与CMOS使用区别
- python读取txt文件并分割成列表_在python中读取文本文件并将其拆分为单个单词
- Linux 中 4 款炫酷的终端应用程序
- 【语言之美】東(dōng)杲(gǎo)杳(yǎo)
- 思科刀片服务器系统,思科UCS平台:B460 M4刀片服务器解读
- 最经典的《资本论》讲座
- Excel 打开无法显示内容
- ART–KOHONEN neural network for fault diagnosis of rotating machinery(翻译)
- 工业控制计算机是微型计算机吗,计算机工业控制复习题及答案