前言
双亲委派模型是一个面试经典题目
类加载
当我们运行java程序时,首先需要将 .java文件经过编译后生成对应 .class文件,然后由 JVM 来加载.class文件到内存中。作为开发人员我们不需要去关心.class文件是如何被加载到 JVM中的,这一切工作都有类加载器去完成。
类的加载过程如图所示:
- 加载,加载分为三步:
1、通过类的全限定性类名获取该类的二进制流;
2、将该二进制流的静态存储结构转为方法区的运行时数据结构;
3、在堆中为该类生成一个class对象;
附jvm内存结构图。 - 验证:验证该class文件中的字节流信息复合虚拟机的要求,不会威胁到jvm的安全;
- 准备:为class对象的静态变量分配内存,初始化其初始值;
- 解析:该阶段主要完成符号引用转化成直接引用;
初始化:到了初始化阶段,才开始执行类中定义的java代码;初始化阶段是调用类构造器的过程;
在第一阶段加载过程中,我们即可以选择使用系统提供的类加载器来完成加载,也可以使用自定义的类加载器来加载。类加载器
在java中,类加载器ClassLoader有四种
- BootStrapClassLoader: c++编写,加载核心库java.*;
- Extension ClassLoader: java编写,加载扩展库javax.*;
- AppClassLoader: java编写,加载程序目录;
- 自定义ClassLoader:java编写,继承自ClassLoader,定制化加载;
双亲委派模型
加载一个类时,先向上委派,实际上就是查找缓存,是否加载了该类,有则直接返回,没有继续向上。委派到顶层后,缓存中还是没有,则到其加载路径中查找,有则对类进行加载,没有继续向下查找。向上委派到顶层类加载器为止,向下查找到发起加载的类加载器为止。
BootstrapClassLoader类加载器负责加载 [jdk根目录]/lib 下的class文件。
ExtClassLoader类加载器负责加载 [jdk根目录]/lib/ext 下的class文件。
AppClassLoader类加载器负责加载用户自定义class类文件。
优点:
1.虚拟机只有在两个类的路径和类名相同且加载该类的加载器均相同的情况下才判定这是一个类。若不采用双亲委派机制,同一个类有可能被多个类加载器加载,这样该类会被识别为两个不同的类,相互赋值时会有问题。双亲委派机制能保证多加载器加载某个类时,最终都是由一个确定加载器加载,确保最终加载结果相同。
2.防止用户自定义一个核心类,如自定义一个String类且路径相同,通过双亲委派模型,jvm并不会去加载用户自定义的String类,而是去加载特定包下的String类。
破坏双亲委派模型
因为类加载器受到加载范围的限制,在某些情况下父类加载器无法加载到需要的文件,这时候就需要委托子类加载器去加载class文件。
JDBC的Driver接口定义在JDK中,其实现由各个数据库的服务商来提供,比如MySQL驱动包。DriverManager 类中要加载各个实现了Driver接口的类,然后进行管理,但是DriverManager位于 JAVA_HOME中jre/lib/rt.jar 包,由BootStrap类加载器加载,而其Driver接口的实现类是位于服务商提供的 Jar 包,根据类加载机制,当被装载的类引用了另外一个类的时候,虚拟机就会使用装载第一个类的类装载器装载被引用的类。也就是说BootStrap类加载器还要去加载jar包中的Driver接口的实现类。我们知道,BootStrap类加载器默认只负责加载 JAVA_HOME中jre/lib/rt.jar 里所有的class,所以需要由子类加载器去加载Driver实现,这就破坏了双亲委派模型。
破坏双亲委派模型同样应用于Tomcat中。
扩展阅读:破坏双亲委派模型
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。