注意:所有文章除特别说明外,转载请注明出处.
第6章 深入分析ClassLoader工作机制
[toc]
ClassLoader是类加载器,负责将Class加载到JVM中。ClassLoader在能够将Class加载到JVM中之外,还有一个重要作用就是审查每个类应该由谁加载,它是一种父优先的等级加载机制。
6.1 ClassLoader类结构分析
ClassLoader中经常用到的方法
1. defineClass(byte[], int, int) 将byte字节流解析成JVM能够识别的Class对象
2. findClass(String)
3. loadClass(String)
4. resolveClass(Class<?>)
defineClass()与findClass()方法一起使用的时候,我们通过直接覆盖ClassLoader父类的findClass()方法来实现类的加载规则,从而取得要加载类的字节码。然后调用defineClass()方法生成类的class对象。
如果不需要重新定义加载规则则可以用 this.getClass().getClassLoader().loadClass(“class”);调用ClassLoader的loadClass()方法获取该类的对象。
ClassLoader还提供另外一些辅助类,如获取class文件的方法:getResource() | getResourceAsStream()方法等。
6.2 ClassLoader等级加载机制
1. Bootstrap ClassLoader 主要加载JVM自身工作需要的类,这个ClassLoader是完全由JVM自己控制。它仅仅是一个类的加载工具,既没有更高一级的父加载器,也没有子加载器。
2. ExtClassLoader 它是JVM中自身的一部分,该类可以理解为加载第三方的类文件。
3. AppClassLoader 它的父类是ExtClassLoader,所有在System.getProperty("java.class.path")目录下的类都可以被这个类加载器加载。该目录就是我们经常用到的classpath。
6.3 加载class文件
1. 找到.class文件并将这个文件包含的字节码加载到内存
2.1 字节码验证
2.2 Class类数据结构分析及相应的内存分配
2.3 符号表的链接
3. 类中静态属性和初始化赋值以及静态块的执行
6.3.1 加载字节码到内存
找到指定类并且将它的字节码加载到内存需要子类中实现(实现findClass()方法)。
6.3.2 验证与解析
1. 字节码验证,这一过程保证格式正确、行为正确。
2. 类准备,准备代表每个类中定义的字段、方法和实现接口所必须的数据结构。
3. 解析,该阶段类装入器装入类所引用的其它所有类。如:超类、接口、字段、方法签名。
6.3.3 初始化Class对象
6.4 类加载错误分析
6.4.1 ClassNotFoundException
该异常发生于在显示加载类的时候。在加载指定字节码到内存时没有找到该文件对应的字节码,也就是该文件不存在。可以通过命令来获取当前的classpath路径。
this.getClass().getClassLoader().getResource("").toString();
6.4.2 NoClassDefFoundError
该异常是可能使用new关键字、属性引用某个类、继承了某个接口或类,以及方法的某个参数中引用某个类,会触发JVM隐式加载这些类时发现类不存在异常。
解决的方案是确保每个类引用的类都在当前的classpath下面。
6.4.3 UnsatisfiedLinkError
6.6 自定义 ClassLoader
ClassLoader完成的事情:
1. 在自定义路径下查找自定义的class类文件,我们需要的class文件并不在classpath下面,所以需要实现ClassLoader。
2. 对要加载的自定义类做特殊处理
3. 可以定义类的时效机制,在检测到类修改,可以重新加载,从而实现热部署