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

相关推荐
紫琪软件工作室2 分钟前
自定义有序Map
java
刘婉晴12 分钟前
【蓝桥杯研究生组】第14届Java试题答案整理
java·蓝桥杯
Upuping25 分钟前
「全网最细 + 实战源码案例」设计模式——外观模式
java·后端·设计模式
等一场春雨1 小时前
Java 21 使用新的日期和时间 API (java.time) 计算当前日期是某活动起始时间的第几天
java·开发语言
南宫生2 小时前
力扣-数据结构-12【算法学习day.83】
java·数据结构·学习·算法·leetcode
KeyPan2 小时前
【数据结构与算法:五、树和二叉树】
java·开发语言·数据结构·人工智能·算法·机器学习·计算机视觉
工业甲酰苯胺2 小时前
Java Web学生自习管理系统
java·开发语言·前端
晚上睡不着!2 小时前
Java程序命令行调用Python矩阵算法
java·开发语言·python·numpy
青木川崎2 小时前
java进阶之maven
java·开发语言·maven
拾荒的小海螺2 小时前
JAVA:Spring Boot 集成 Quartz 实现分布式任务的技术指南
java·spring boot·分布式