Java虚拟机:类加载器与双亲委派模型

一、类加载器:

类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机默认提供了3种类加载器,引导类加载器(Bootstrap)、扩展类加载器(Extension)、应用类加载器(AppClassLoader),如果有必要还可以加入自己定义的类加载器。

 

对于任意一个类,都需要由加载它的类加载器和类的全限定名一同确定其在Java虚拟机中的唯一性。因此,比较两个类是否“相等”的前提是这两个类是由同一个类加载器加载的,否则,即使两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。

 

二、类加载器说明:

(1)启动类加载器(Bootstrap ClassLoader):这个类加载器负责将存放在\lib目录中,或者被-Xbootclasspath虚拟机参数指定的路径中,并且是虚拟机识别的类库加载到虚拟机内存中。(仅按照文件名识别,如rt.jar,名称不符合的类库即使放在lib目录中也不会被加载。)

(2)扩展类加载器(Extension ClassLoader):这个类加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

(3)应用程序类加载器(Application ClassLoader):这个类加载器由sun.misc.Launcher$ApplicationClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

(4)CustomClassLoader(自定义加载器):属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现。

 

三、双亲委派模型:

上面介绍的几种类加载器之间的关系如下图,类加载器之间的层次关系,称为类加载器的双亲委派模型。双亲委派模型要求除了顶层的启动类加载器外,其余类加载器都应该有自己的父类加载器。这里类加载器之间的父子关系一般不会以继承的关系实现,而是使用组合关系来复用父加载器的代码。

Java虚拟机:类加载器与双亲委派模型_第1张图片

 

1、类加载器的顺序: 
(1)加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader、Application ClassLoader、Extension ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。 
(2)Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null。

2、双亲委派模型的工作过程:

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该首先传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

3、双亲委派模型的优点:

使用双亲委派模型来组织类加载器之间的关系,Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如,类java.lang.Object,它存放在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给模型最顶端的启动类加载器进行加载,因此Object类在程序的各个类加载器环境中都是同一个类。通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。双亲委派模型很好的解决了各个类加载器的基础类的统一问题,越基础的类由越上层的加载器进行加载。

相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基本的行为也就无法保证,应用程序也会变得一片混乱。

 

你可能感兴趣的:(JVM虚拟机)