最近学习《高琪300集》的手写servlet,对于底层的原理不是很理解,于是想研究类加载器,以下是在网上收集整理的笔记,并非原创,文章末尾补充了原文地址。
version:jdk.1.8
定义:类加载器的具体作用就是将class文件加载到jvm虚拟机中。
Class文件:字节码文件,用IDE编写的Java文件经过编译,生成class文件,jvm不能直接运行Java文件,需要把Java文件编译成class文件
Java环境变量:JAVA_HOME、PATH、CLASSPATH
JAVA_HOME:指定JDK的位置
PATH:将程序路径包含在PATH当中后,在命令行就可以直接键入它的名字,不需要键入它的全路径,比如需要用到的javac和java两个命令
CLASSPATH:指向jar包 CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
JAVA类加载流程:
类加载器:
Bootstrap ClassLoader(引导程序):最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的rt.jar、resources.jar\charsets.jar和class等。另外需要注意的是可以通过启动jvm时指定-Xbootclasspath和路径来改变Bootstrap ClassLoader的加载目录。
Extention ClassLoader(扩展的类加载器):加载目录%JRE_HOME%\lib\ext目录下的和class文件。
Appclass Loader(SystemAppClass):加载当前应用的classpath的所有类。
加载顺序:
顺序:1、Bootstrap ClassLoader----->2、Extention ClassLoader----->3、AppclassLoader
可以通过System.getProperty(“环境变量”);查看
通过直接输出ClassLoader,System.out.println(Object.class.getClassLoader.toString())可以观察到自己创建的类,为AppClassLoader加载,而int、String为null,这是因为int、String由BootstrapClassLoader加载为什么这里没有明确的类加载器,而是null
每个类加载器都有一个父加载器

1、Object.class.getClassLoader()---------------------->AppclassLoader
2、AppclassLoader.getParent()------------------------->ExtClassLoader/PlatformClassLoader in v 1.4
3、ExtClassLoader/PlatformClassLoader.getParent()----->null
结论:AppclassLoader的父类为ExtClassLoader,但ExtClassLoader的父类为null不是说每个加载器都有一个父类的吗?
父加载器不是父类,ExtClassLoader/PlatformClassLoader、AppclassLoader继承自URLClassLoader,其实就是通过构建的时候赋予一个ClassLoader,指定为其parent,比如AppClassLoader由ExtClassLoader构建至于BootstrapClassLoader怎样创建的呢?ExtClassLoader/PlatformClassLoader父加载器为null,但BootstrapClassLoader缺可以当成它的父加载器?
Bootstrap ClassLoader是由C++编写的
Bootstrap ClassLoader是由C/C++编写的,它本身是虚拟机的一部分,所以它并不是一个Java类,也就是说无法通过Java代码获取它的引用,JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件,之前的int.class,String.class都是由它加载。
双亲委托:一个类加载器查找class和resource时,是通过“委托模式”进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到Bootstrap ClassLoader,如果Bootstrap classloader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象。这种机制就叫做双亲委托。
1、一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器
2、递归,重复第一部分的操作
3、如果ExtClassLoader加载不成功,则由BootstrapClassLoader出面,它首先查看缓存,如果没有找到的话,就去找自己规定的路径下,找相关资源,找到就返回,没找到就让自家在其找
4、Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回,查找不成功,再向下让子加载器找。
5、ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回。如果没有找到就让子类找,如果没有子类会怎么样?抛出各种异常。

重要方法:loadClass()、findLoadedClass()、findClass()、defineClass()…
自定义ClassLoader:因为BootstrapClassLoader和ExtClassLoader都只能加载指定的目录下的jar包或者资源,那么想要动态加载一些东西,我们可以自定义classLoader
具体定义方法:略 ,参考:https://blog.csdn.net/briblue/article/details/54973413?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1
ContextClassLoader线程上下文类加载器:是Thread的一个成员变量,每个Thread都有一个相关联的ClassLoader,默认为AppClassLoader,并且子线程默认使用父线程的ClassLoader。
总结:
1、ClassLoader用来加载class文件的。
2、系统内置的ClassLoader通过双亲委托来加载指定路径下的class和资源。
3、可以自定义ClassLoader一般覆盖findClass()方法。
4、ContextClassLoader与线程相关,可以获取和设置,可以绕过双亲委托的机制。
参考: 一看你就懂,超详细java中的ClassLoader详解 CSDN博主「frank909」的原创文章 原文链接:https://blog.csdn.net/briblue/article/details/54973413.
相关文章:
-
2021-03-31
-
2021-07-04
-
2021-11-16
-
2022-12-23