Java双亲委派模型

Posted 每日一算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java双亲委派模型相关的知识,希望对你有一定的参考价值。

技术文章第一时间送达!


最近总结了一下JVM虚拟机的内容,首先来看下Java类的双亲委派模型。




可以看到应用类加载器的父加载器是扩展类加载器,扩展类加载器的父加载器是启动类加载器。


那么这三种类加载器的定义是什么呢?


启动(Bootstrap)类加载器:
启动类加载器是用本地代码实现的类加载器,它负责将<JAVA_HOME>/lib下面的核心类库
或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中。由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。


扩展(Extension)类加载器
扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的,它负责将<JAVA_HOME >/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。


系统(System)类加载器
系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的,它负责将用户类路径(java -classpath或-Djava.class.path变量所指的目录,即当前类所在路径及其引用的第三方类库的路径下的类库加载到内存中。开发者可以直接使用系统类加载器。


下面我们可以看一个例子


Java双亲委派模型


当执行上面的代码,打印的结果如下


Java双亲委派模型


可以看出当前的类加载器是AppClassLoader,它的父类加载器是ExtClassLoader,它的父类的父类加载器打印出来的是null。这是因为由于启动类加载器无法被Java程序直接引用,因此JVM默认直接使用 null 代表启动类加载器


理解完了定义之后,再来看看JVM在加载类时默认采用的双亲委派机制。其工作原理是如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。


那么为什么要有双亲委派机制呢?


采用双亲委派模式的好处是Java类可以避免重复加载,当父亲已经加载过该类时,就没有必要子加载器再加载一次。


其次是考虑到安全因素,java核心的api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,就不会重新加载网络传递的过来的java.lang.Integer,而是直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。