看过很多讲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
-------------------------------------------------------------------------------------------------------------------------------