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

相关推荐
pianmian126 分钟前
类(JavaBean类)和对象
java
我叫小白菜1 小时前
【Java_EE】单例模式、阻塞队列、线程池、定时器
java·开发语言
Albert Edison1 小时前
【最新版】IntelliJ IDEA 2025 创建 SpringBoot 项目
java·spring boot·intellij-idea
超级小忍2 小时前
JVM 中的垃圾回收算法及垃圾回收器详解
java·jvm
weixin_446122462 小时前
JAVA内存区域划分
java·开发语言·redis
勤奋的小王同学~2 小时前
(javaEE初阶)计算机是如何组成的:CPU基本工作流程 CPU介绍 CPU执行指令的流程 寄存器 程序 进程 进程控制块 线程 线程的执行
java·java-ee
TT哇2 小时前
JavaEE==网站开发
java·redis·java-ee
2401_826097623 小时前
JavaEE-Linux环境部署
java·linux·java-ee
缘来是庄3 小时前
设计模式之访问者模式
java·设计模式·访问者模式
Bug退退退1234 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq