类加载器双亲委托机制详解

理论了解:

关于类加载器的双亲委托机制基本上都听说过,面试时可能偶尔也会被问到,但是可能都是网上去找了一个理论性的答案临时了解了一下,并未对它到底是个什么样的机制有深入的了解,所以接下来准备深入了解它,在了解之前当然得有理论做为支撑。

在之前【http://www.cnblogs.com/webor2006/p/8905978.html】已经对类加载器的一个层次关系有了一个大体的了解,回顾一下:

在父亲委托机制中,各个加载器按照父子关系形成了树形结构【注意:并非物理上的树形结构,而是逻辑上的树形结构】,附了根类加载器之外,其余的类加载器都有且只有一个父加载器。下面来看另外一张图:

其中loader1和loader2是自定义类加载器,所谓的类加载器的双亲委托机制是这样:假如说想要通过loader1来加载自己所编写的Sample类,而类加载器双亲委托机制并不是直接由loader1直接来加载Sample类,而是先转交给loader1的父亲系统类加载器来完成,而系统类加载器又会转交给扩展类加载器去完成, 而由于扩展类加载器还有父亲根类加载器,所以说又会转到根类加载器去加载,由于它木有父加载器了,此时根类加载器就开始尝试去加载Sample类了,但是!此时根类加载器是无法加载Sample类的,为什么?原因如下:

也就是说此时根类加载器会加载失败,但是并不是失败了就立马就返回了,而是把加载的任务又返回给它的下一级子类,也就是扩展类加载器,而扩展类加载器也加载不了自定义的类,原因跟根类加载器类似,如下:

也就是不进行相应路径的配置其扩展类加载器加载Sample类肯定也失败了,于是继续传给它的下一级子类系统类加载器(也叫应用加载器),而它加载的规则如下:

也就是一般情况下系统类加载会成功的加载咱们定义的Sample类了,通过这么一个从底部往上和从顶部往下的过程其实最终加载Sample类是由系统类加载器完成的,而非是load1完成,不过会将结果返回给load1,以上的整个过程则为双亲委托机制(也叫父亲委托机制),大体可以归纳为:某一个类加载器想要加载一个类,它并非立马自己去加载该类,而是委托给它的父亲去加载,如果父亲还有父亲则继续委托,直到根类加载器了没父亲了则由它去加载,如果加载不成功则会从上到下进行委托加载,整个链上只要有一个加载器能加载成功,则最终的加载结果就是成功的,最终流程就会返回到第一次想加载类的类加载器。

【注意】:上面的加载机制只是在标准的hospot虚拟机上是这样的,当然JDK里采用的也是标准的这种方式,但是不并代码其它的JVM都是采用的这种双亲委托机制,了解一下。

再来看一下该图:

这个顺序刚好就是咱们之前所描述的。下面再针对不同的加载类具体描述一下其加载的特性:

  • Bootstrap ClassLoader【启动类加载器】:负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类。
  • Extension ClassLoader【扩展类加载器】:负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包。
  • App ClassLoader【系统类加载器/应用类加载器】:负责加载classpath中指定的jar包及目录中的class。

另外还需了解一个概念,仅了解既可:如果有一个类加载器能够成功加载Test类,那么这个类加载器被称为定义类加载器,所有能成功返回Class对象引用的类加载器(包括定义类加载器)都被称为初始类加载器。具体理解如下:

实验:

既然已经对类加载器的双亲委托机制有了一定的了解,下面编写代码来使用一下类加载器:

在加载自定义类之前,咱们先来加载系统的类,如下:

在运行之前,先来看一下getClassLoader()这个方法的说明:

编译运行:

这也是根类加载器的职责所在,再来回顾下:

好,那接下来再来加载咱们自己定义的类C,如下:

而AppClassLoader的职责如下:

那咱们来看一下AppClassLoader类:

位置Launcher类中,而这个类是ide根据class文件反编译出来的,因为它并不是开源的,如下:

其中了解一下它的类继承关系:

原文地址:https://www.cnblogs.com/webor2006/p/9016996.html