JVM类的加载机制双亲委派

看过很多讲JVM类加载的文章,觉得不够通俗,下面是我总结的,希望能帮到各位,会持续更新,后续也会写的清楚一点

---------------------------------------------------------------------------------------------------------------------------------

java.exe调用底层的jvm.dll文件创建java虚拟机(C++实现)

java.exe 底层C或C++实现,通过C++实现的代码调用C、C++语言的库函数jvm.dll,创建java虚拟机。

dll文件相当于java的jar包。

C++语言的启动程序,整了一个JVM,然后JVM会创建很多java实现的类加载器,通过这些类加载器去真正调用类加载器里面loadClass方法,去加载磁盘上的字节码文件。

加载到内存之后,C语言会直接调用main方法。

-------------------分隔符----------------------------------------上面是对jvm简单印象------------------------------

记得很多年前,我们更新项目,如果小改动或者打个小补丁,都是直接替换class文件,然后重启即可。

有没有考虑过target里面的.class文件是什么样的,如何加载到内存里的,其实这个过程就是类加载。

javap -v  类名.class 能把字节码文件转换成可读性高一点的内容,但是两者是一个文件,无区别,只是可读性好一点。(想读的可以百度下字面量)

验证:是否符合规范

准备:静态变量赋一个初始值,int为0  boolean为false

解析:用人话解释 符号引用替换为直接引用,比如main方法加载到内存中是有内存地址的(方法在内存区域的一个位置或地址),main这种静态的名称就是符号,它的位置就是代码的直接引用。

初始化:静态变量初始化为指定值,执行静态代码块

其实这也就解释了,为什么在类里定义的静态变量会在项目启动的时候就加载好了

注意:new 对象名();   属于引用 ,会执行该类里的静态代码,

类名  变量名 = null; 不会执行类里的静态代码。

-----------------------------------------------------------------分隔符-------------------------------------------------------

java语言怎么实现类加载的

首先,要明白类加载器的概念

注意途中红色箭头,类加载器的名字,再对照jre目录,就能明白,

引导类加载器:这个类加载器对象不是java对象,是C++的对象,所以看不到

扩展类加载器: 叫Ext,加载的是ext目录下的类

应用程序类加载器:叫App,加载的是自己写的类

这两个都是Launcher类下的。

Launcher类是JVM启动器里面非常核心的一个类。 (中文翻译:启动器;桌面启动器;桌面;枪炮师;发射器)。

C++再创建好引导类加载器之后,它会通过C++代码调用Java代码里的Launcher类,它会初始化这个Launcher类,Launcher类就是JVM类加载器的一个启动器,它初始化这个Launcher类之后,再加载其他类。在初始化Launcher类的过程中,会把其他四个类加载器全部生成出来。

------------------------------------------------------------------------------------------------------------------

所有的类加载器,都继承自ClassLoader。

Launcher.getLauncher();

(这个还是写在这里,比较直观,以后再拆分,现在写的很细,会有些乱)

URLClassLoader后续再说,这个类会通过读取路径,把文件加载到内存中,先知道即可。

一路跟进去,注意图中箭头和红框

由此可发现:

1、在初始化Launcher类的过程中,会把ExtClassLoader和AppClassLoader初始化。

2、AppClassLoader的parent是ExtClassLoade,ExtClassLoader的的parent是null(引导类加载器,没有)。(parent是一个属性,为ClassLoader,见URLClassLoader)

其实Ext的ClassLoader算是引导类加载器,到是引导类加载器是C++写的。

---------------------------------------------------------------------------------------------------------------------------------可以打印加载的内容,用图中的代码.

会发现App和Ext加载的内容,就体现了双亲委派,有些虽然打印出来了,但是不会再加载。

双亲委派流程用人话讲:

比如加载一个自己写的类A,

1、首先通过应用程序类加载器去加载,它会先检查有没有加载,如果有直接返回,如果没有就向上委托,让父加载器去加载,就这样,一直到引导类加载器,必然不会找到我自己写的A类。

2、既然引导类加载器也找不到,就会向下级委托加载,一直这样,到应用程序类加载器,它会到ClassPath下面找,这样就能找到了。

注意:这里说不是父类的意思,是父加载器

加载自定义类的都是应用程序类加载器,源码就这么写的,

可以跟一下launcher.getClassLoader(),下面图里有。

要考虑为什么这么做:

jvm开发人员才知道,我只是猜测,

1、web应用程序95%都是自己写的类,都是应用程序类加载器加载,只有第一次加载的时候,才会循环走一遍,以后再用,直接在程序类加载器就能拿到结果。

如果都从引导类走,那95%的类,都要走一遍上面的两个类,每次加载都要走。

走源码的话,后期我会出视频,现在写文字太多了,截了几张图,可以看下。

URLClassLoader里的findClass才是去拿文件的,装载到内存调用的是defineClass方法,跟到最后还是native本地方法。

记住Ext是加载不到自定义类的,因为是嵌套调用,会继续用App去记载。看源码注意此时执行的是哪一个加载类,这个加载类的父类是谁。

-----------------------------------------------------------------------------------------------------------------------------

那为什么要用这种机制呢

1、沙箱安全机制,防止核心API库呗随意篡改

2、避免类的重复加载,保证加载类的唯一性

可以自己写个Sring类试试,参考图中类包名类名,最终会有引导类加载器返回JDK中的String,但是找不main方法,就会报错

---------------------------------------------------------------------------------------------------------------------------------全盘委托机制,这是一个简单额度设计,内容如图。

---------------------------------------------------------------------------------------------------------------------------------

自定义类加载器

核心方法就是加载类的逻辑

根据位置找到这个类,再做一系列的加载逻辑。

重新findClass方法

继承ClassLoader 类

注意,ClassLoader 类中的findClass方法是一个空实现,是要重写的。

defineClass方法调用一系列本地方法,进行加载,复用即可

----------------------------------------------

自定义类加载器 默认的父加载器是 应用程序类加载器(源码可以看图,初始化时传的是Launcher里的ClassLoader,Launcher的ClassLoader就是AppClassLoader),自定义类加载器 也遵守双亲委派。

为什么这样设计? 还是为了满足双亲委派机制。

---------------------------------------------------------------------------------------------------------------------------------

打破双亲委派机制

这个先说下思路吧,今天没时间写了,改天出个视频。

直接用自定义类加载器加载,不让父加载器加载

1、在加载类的时候,调用的是loadClass方法,我复制这个方法到自己的类加载器,重写即可,修改双亲委派的规则。

2、修改加载规则,比如:如果是需要打破双亲委派机制的类,就直接用自定义加载器加载。

如果是其他类,则走双亲委派机制,如:Object类

---------------------------------------------------------------------------------------------------------------------------------

Tomcat是否打破双亲委派机制

打破了

主要是为了不同项目,隔离运行,这个改天会出一份详细的资料

https://blog.csdn.net/b416055728/article/details/121455040

-------------------------------------------------------------------------------------------------------------------------------

 

 

猜你喜欢

转载自blog.csdn.net/b416055728/article/details/121436217