ClassLoader 的基本目标是对类的请求提供服务。当JVM需要使用类时,它根据名称向ClassLoader请求这个类,然后ClassLoader试图返回一个表示这个类的Class对象。
通过覆盖对应这个过程的不同阶段的方法,可以创建定制的ClassLoader。
1. 方法loadClass
ClassLoader.loadClass()是ClassLoader的入口点。
Class loadClass(String name, boolean resolve);
name 参数指定了JVM需要的类的名称,该名称以包表示法表示。
resolve 参数告诉方法是否需要解析类。在准备执行类之前,应考虑类解析。并不总是需要解析。如果JVM只需要知道该类是否存在或找出该类的超类,那么就不需要解析.
2.方法defineClass
final 方法.
defineClass是ClassLoader的主要诀窍。该方法接受由原始字节组成的数组并把它转换成Class对象。原始数组包含如从文件系统或网络装入的数据.
defineClass管理JVM的许多复杂,神秘和依赖与实现的方面。它把字节码分析成运行时的数据结构,校验有效性等等。
3.方法findSystemClass
findSystemClass 从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就是用 defineClass将原始字节转换成Class对象,以将该文件转换成类。当运行JAVA应用程序时
这是JVM正常装入类的缺省机制.
对于定制的ClassLoader,只有在尝试其他方法装入类之后,再使用findSystemClass。原因很简单:ClassLoader是负责执行装入类的特殊步骤,不是负责所有类。
例如,即使ClassLoader从远程WEB站点装入了某些类,仍然需要在本地机器上装入大量的基本JAVA库。而这些类不是我们所关心的,所以要JVM以缺省机制装入他们:从本地文件系统装入。这
就是findSystemClass的用途.
4.方法resolveClass
可以不完全地(不带解析)装入类,也可以完全的(带解析)装入类。当编写我们自己的loadClass时,可以调用resolveClass,这取决于loadClass的resolve参数的值。
5.方法findLoadedClass
findLoadedClass充当一个缓存:当请求loadClass装入类时,它调用该方法来查看ClassLoader是否已经装入了这个类,这样可以避免重新装入已经存在的类所造成的麻烦。应首先调用该方法。
组装
我们的loadClass实现示例执行以下步骤(这里,我们没有指定生产类文件时采用哪种技术,它可以是从NET上装入,或者从归档文件中提取,或者实时编译。无论是那一种,都使我们获得了原始类文件字节)
1>调用findLoadedClass来查看是否已存在装入的类
2>如果没有,那么采用上面的几种方式的一种来获取原始字节
3>如果已有原始字节,调用defineClass将他们装换成Class对象
4>如果没有原始字节,然后调用findSystemClass查看是否从本地文件系统中获取类
5>如果resove参数是true,那么调用resoveClass解析ClassLoader对象
6>如果还没有类,返回ClassNotFoundException
7>否则,将类返回给调用程序
CompilingClassLoader
1>当请求一个类时,先检查它是否存在磁盘的当前目录或相应的子目录
2>如果该类不存在,但源码中有,那么调用JAVA编译器来生成类文件
3>如果该类已存在,检查它是否比源码旧。如果是,调用JAVA编译器来重新生成类文件
4>如果编译失败,或者由于其他原因不能从现有的源码中生成类文件,返回ClassNotFoundException
5>如果仍然没有该类,也许它在其他库中,所以调用findSystemClass来寻找该类
6>如果还是没有,则返回ClassNotFoundException
7>否则,返回该类