Classloader 类加载器,用来加载Java类到 Java 虚拟机中的一种加载器。
作用:
ClassLoader的具体作用就是将class文件加载到jvm虚拟机
注:
隐式加载:不通过在代码里调用ClassLoader来加载需要的类,而是通过JVM来自动加载需要的类到内存,例如:当类中继承或者引用某个类时,JVM在解析当前这个类不在内存中时,就会自动将这些类加载到内存中。
显示加载:在代码中通过ClassLoader类来加载一个类,例如调用this.getClass.getClassLoader().loadClass()或者Class.forName()。
前提:
java程序并不是一个可执行的文件,
而是由多个独立的类文件组成的,
每个文件对应一个java类
此外,这些文件并非全部装入内存,而是根据程序需要逐渐载入
Java语言系统自带有三个类加载器:
Bootstrap ClassLoader:最顶层的加载类,主要加载核心类库,%JRE_HOME%lib下的rt.jar、resources.jar、charsets.jar和class等;
Extention ClassLoader:扩展的类加载器,加载目录%JRE_HOME%libext目录下的jar包和class文件;
Appclass Loader:也称为SystemAppClass,加载当前应用的classpath的所有类;
AppClassLoader的父加载器是ExtClassLoader,而ExtClassLoader的父加载器是BootstrapClassLoader。
注:父加载器不是父类,不能通过getParent()判定。
全盘负责 是指当一个ClassLoader装载一个类时,除非显示地使用另一个ClassLoader,则该类所依赖及引用的类也由这个CladdLoader载入。
双亲委托
JVM加载一个class时先查看是否已经加载过,没有则通过父加载器,然后递归下去,直到BootstrapClassLoader,如果BootstrapClassloader找到了,直接返回,如果没有找到,则一级一级返回(查看规定加载路径),最后到达自身去查找这些对象。
“双亲委派”机制:真正加载class字节码文件生成Class对象
1. 源ClassLoader先判断该Class是否已加载,如果已加载,则返回Class对象;如果没有则委托给父类加载器。
2. 父类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则委托给祖父类加载器。
3. 依此类推,直到始祖类加载器(BootstrapClassLoader)。
4. 始祖类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则尝试从其对应的类路径下寻找class字节码文件并载入。如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的子类加载器。
5. 始祖类加载器的子类加载器尝试从其对应的类路径下寻找class字节码文件并载入。如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的孙类加载器。
6. 依此类推,直到源ClassLoader。
好处是:
- 避免重复加载
- A和B都需要加载X,各自加载就会导致X加载了两次,JVM中出现两份X的字节码;
- 防止恶意加载
- 编写恶意类java.lang.Object,自定义加载替换系统原生类;
常见的例子:Class.getResource()是通过委托给ClassLoader的getResource()
JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。
当需要自定义classLoader
如下列情况:
- 我们需要的类不一定存放在已经设置好的classPath下(有系统类加载器AppClassLoader加载的路径),对于自定义路径中的class类文件的加载,我们需要自己的ClassLoader
- 有时我们不一定是从类文件中读取类,可能是从网络的输入流中读取类,这就需要做一些加密和解密操作,这就需要自己实现加载类的逻辑,当然其他的特殊处理也同样适用。
- 可以定义类的实现机制,实现类的热部署,如OSGi中的bundle模块就是通过实现自己的ClassLoader实现的。
其他classLoader下具体方法等有遇到在详细记录,这次只是初步了解下