扫码关注公众号

JVM考点之类加载器和双亲委派
12-10
16观看
01

为什么需要双亲委派?

因为类加载器之间有严格的层次关系,那么也就使得Java类也随之具备了层次关系。或者说这种层次关系是优先级。比如一个定义在java.lang包下的类,因为它被存放在rt.jar之中,所以在被加载过程汇总,会被一直委托到BootstrapClassLoader,最终由BootstrapClassLoader所加载。而一个用户自定义的com.hollis.ClassHollis类,他也会被一直委托到BootstrapClassLoader,但是因为BootstrapClassLoader不负责加载该类,那么会在由ExtentionClassLoader尝试加载,而ExtentionClassLoader也不负责这个类的加载,最终才会被ApplicationClassLoader加载。这种机制有几个好处。首先,通过委派的方式,可以避免类的重复加载,当父加载器已经加载过某一个类时,子加载器就不会再重新加载这个类。另外,通过双亲委派的方式,还保证了安全性。因为BootstrapClassLoader在加载的时候,只会加载JAVA_HOME中的jar包里面的类,如java.lang.Integer,那么这个类是不会被随意替换的,除非有人跑到你的机器上,破坏你的JDK。那么,就可以避免有人自定义一个有破坏功能的java.lang.Integer被加载。这样可以有效的防止核心JavaAPI被篡改。

来自:jvm虚拟机相关-类的加载过程
02

"父子加载器"之间的关系是继承吗?

很多人看到父加载器、子加载器这样的名字,就会认为Java中的类加载器之间存在着继承关系。甚至网上很多文章也会有类似的错误观点。这里需要明确一下,双亲委派模型中,类加载器之间的父子关系一般不会以继承(Inheritance)的关系来实现,而是都使用组合(Composition)关系来复用父加载器的代码的。如下为ClassLoader中父加载器的定义:

来自:jvm虚拟机相关-类的加载过程
03

双亲委派是怎么实现的?

双亲委派模型对于保证Java程序的稳定运作很重要,但它的实现并不复杂。实现双亲委派的代码都集中在java.lang.ClassLoader的loadClass()方法之中:代码不难理解,主要就是以下几个步骤:1、先检查类是否已经被加载过2、若没有加载则调用父加载器的loadClass()方法进行加载3、若父加载器为空则默认使用启动类加载器作为父加载器。4、如果父类加载失败,抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载。

来自:jvm虚拟机相关-类的加载过程
04

如何主动破坏双亲委派机制?

知道了双亲委派模型的实现,那么想要破坏双亲委派机制就很简单了。因为他的双亲委派过程都是在loadClass方法中实现的,那么想要破坏这种机制,那么就自定义一个类加载器,重写其中的loadClass方法,使其不进行双亲委派即可。

来自:jvm虚拟机相关-类的加载过程
05

Tomcat是如何打破双亲委派机制的?

如上图,上面的橙色部分还是和原来一样,采用双亲委派机制。而黄色部分是tomcat第一部分自定义的类加载器,这部分主要是加载tomcat包中的类,这一部分依然采用的是双亲委派机制,而绿色部分是tomcat第二部分自定义类加载器,正是这一部分,打破了类的双亲委派机制。

来自:jvm虚拟机相关-类的加载过程
专栏
java语言-jvm虚拟机相关-类的加载过程
3专栏
0课程
5 试题