jar -jar运行原理

jar -jar运行原理

1.前言

阅读这篇文章你将知道

jar包是如何被jvm加载,并运行起来的。

jvm的classload如何进行加载

springboot对象的生命周期啥时候开始的

2.提问

平时我对于java代码是如何运行起来的缺少认知,那么java代码是如何运行起来的呢?

3.前置知识

jvm类加载原理:双亲委派基金,二进制字节码,spi知识点需要复习,jar包的结构

jar包的结构如下:

run.jar

|------org

| |------springframework

| |------boot

| |------loader

| |------JarLauncher.class

| |------Launcher.class

|------META-INF

| |------MANIFEST.MF

|------BOOT-INF

| |------class

| |------Main.class

| |------Begin.class

| |------lib

| |------commons.jar

| |------plugin.jar

| |------resource

| |------a.jpg

| |------b.jpg

4.运行原理

在idea中我们点击运行其实经历了以外几步:1.clean->compile→install(其实就是编译和打包),得到一个jar包

编译的过程其实就是将java代码,编译成一个一个.class文件(二进制字节码),这个也是jvm的一个优点,二进制字节码是脱离语言而存在的,这里就能体现一次编码,到处都可以运行。

java真正运行起来是通过jar -jar来进行的,那么jar -jar完会直接去找Main-Class

即找到META-INF下面的MANIFEST.MF文件里的Main-Class的属性值。也就是org.springframework.boot.loader.JarLauncher,这是一个用于jar这种归档文件的启动器,它的直接父类是ExecutableArchiveLauncher类,这个父类有两个子类,另一个是WarLauncher,然后会执行里面一个入口方法,也就是main方法

main方法里创建了一个JarLauncher实例,并执行了它的一个launch方法,这个方法位于父类Launcher类中,通过一个getClassPathArchives方法获取到我们执行的那个jar归档文件

然后通过getNestedArchives方法获取到boot-inf里面的第三方jar包和项目中的信息,也就是嵌套的jar文件,随后创建一个LaunedURLClassloader(自定义类加载器),把Launcher这个类的类加载器作为它的父类加载器,并且把线程上下文类加载器设置成该类加载器,这个类加载器是springboot自定义的类加载器,用于加载jdk提供的类加载器所加载不到的被嵌套的jar文件和项目类信息,

拿到Start-class的属性值,也就是我们自己定义的springbootapplication的启动类,用这个类加载器去加载这个启动类, 接下来通过反射的方式去执行main方法

springbootapplication启动之后会进行spring对象生命周期的过程中,通过autoconfigration还有扫描注解将bean加载到springfactory里面

注意:jar -jar第一步是将所有的字节码存入内存,但是并不是所有的内容都加载到classloader里面,jvm是对特定的对象通过双亲委派来进行加载到内存的

5.classpath的几种读取方式

5.1 classpath是啥

classpath是存放.class文件的根路径,这个根路径是如何获取到呢,是在jdk源码classloader包里面有定义,被定义为classloader的资源.

5.2 classpath的读取方式

由于classpath的数据来源是jdk,classloader,spring还有线程读取classload的方式都是异曲同工,原理都是调用classload的getResource方法,常用的方法有:

5.2.1 class.getClassloader()

Class.getResource(String path)

path不以'/'开头时,默认是从此类所在的包下取资源;path以'/'开头时,则是从项目的ClassPath根下获取资源。在这里'/'表示ClassPath

JDK设置这样的规则,是很好理解的,path不以'/'开头时,我们就能获取与当前类所在的路径相同的资源文件,而以'/'开头时可以获取ClassPath根下任意路径的资源。

5.2.2.classload.getResource()

Class.getClassLoader().getResource(String path)

path不能以'/'开头时,path是指类加载器的加载范围,在资源加载的过程中,使用的逐级向上委托的形式加载的,'/'表示Boot

5.2.3.resourceUtil.getURL("classpath:").getPath() (springboot的方式)

这种方式其实是封装了classload.getResouce方式即获取当前线程类加载器 然后去获取classloder的资源

6参考

https://blog.csdn.net/gml0000/article/details/105334331

https://blog.csdn.net/l18848956739/article/details/97514462

相关推荐
·云扬·1 分钟前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1231 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠1 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.1 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象
全栈凯哥1 小时前
02.SpringBoot常用Utils工具类详解
java·spring boot·后端
兮动人1 小时前
获取终端外网IP地址
java·网络·网络协议·tcp/ip·获取终端外网ip地址
呆呆的小鳄鱼1 小时前
cin,cin.get()等异同点[面试题系列]
java·算法·面试
独立开阀者_FwtCoder2 小时前
"页面白屏了?别慌!前端工程师必备的排查技巧和面试攻略"
java·前端·javascript
Touper.2 小时前
JavaSE -- 泛型详细介绍
java·开发语言·算法
静若繁花_jingjing2 小时前
Redis线程模型
java·数据库·redis