Java虚拟机类加载器--双亲委派模型
1. 双亲委派模型介绍
JVM对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。
而且加载某个类的class文件时,每个类都有一个对应它的类加载器,系统中的ClassLoader在协同工作的时候会默认使用双亲委派模型。
即,当某个类加载器需要加载某个.class字节码文件时,它首先把这个任务委托给它的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
它是一种任务委派模式。
2. 双亲委派模型的工作原理?
【1】如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去执行;
【2】如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;(每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中。)
【3】如果父类加载器可以完成类加载任务,就成功返回;倘若父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。
以上便是双亲委派模型的工作原理。
双亲委派模型对于保证Java程序的稳定运作极为重要,但它的实现却异常简单,用以实现双亲委
派的代码只有短短十余行,全部集中在java.lang.ClassLoader的loadClass()方法之中。
举个栗子:
public class ClassLoaderDemo {public static void main(String[] args) {System.out.println("ClassLoaderDemo's ClassLoader is ========================> " + ClassLoaderDemo.class.getClassLoader());System.out.println("The Parent of ClassLoaderDemo's ClassLoader is ==========> " + ClassLoaderDemo.class.getClassLoader().getParent());System.out.println("The GrandParent of ClassLoaderDemo's ClassLoader is =====> " + ClassLoaderDemo.class.getClassLoader().getParent().getParent());}
}
测试结果:
ApplicationClassLoader的父类加载器是ExtClassLoader
ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader
没有父类加载器,而是 BootstrapClassLoader
。
其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方 API 文档对这部分的描述如下:
The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
3. 双亲委派模型实现源码分析
双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在java.lang.ClassLodaer的loaderClass()中,相关代码如下所示:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{synchronized (getClassLoadingLock(name)) {// 首先,检查请求的类是否已经被加载过Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {//如果存在父类加载器,则取找该类的父类加载器c = parent.loadClass(name, false);} else {//父类加载器为空,则使用启动类加载器c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// 如果父类加载器抛出ClassNotFoundException异常// 则说明父类加载器无法完成加载请求}if (c == null) {// 在父类加载器无法加载时// 再调用本身的findClass方法来进行加载// 也就是自己尝试加载long t1 = System.nanoTime();c = findClass(name);// 这是定义类加载器;记录统计数据sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}
}
这段源码逻辑:
【1】首先,在类加载时,系统先检查请求加载的类型是否已经被加载过,已经被加载的类会直接返回,倘若没有则调用父类加载器loadClass()方法,才会尝试加载;
【2】加载的时候,首先把该加载请求委派给父类加载器的loadClass()方法处理,如果父类加载器为空,则默认使用启动类加载器作为父加载器。
【3】如果父类加载器加载失败,抛出ClassNotFoundException异常,这时候才调用自己的findClass()方法尝试进行加载。
可参考网上的双亲委派模型流程图:
4. 双亲委派机制的好处?
【1】保证了Java程序的稳定运行,避免类的重复加载,保证基础类仅加载一次,不会让JVM中存在重名的类。
防止重复加载同一个.class文件,比如String.class,每次加载都委托给父加载器,最终都是BootstrapClassLoader,都保证java核心类都是BootstrapClassLoader加载的,加载过了,就不用再加载一遍,保证了java的安全与稳定性。
【2】保护程序安全,防止核心.class文件被随意篡改。
通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class
对象。这样保证了Class
执行安全。
如果不想使用双亲委派模型时,该如何做?
自定义加载器的话,需要继承 ClassLoader。
如果我们不想打破双亲委派模型,就重写 ClassLoader类中的 findClass()方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。
但是,如果想打破双亲委派模型则需要重写 loadClass()方法
5. 如何不使用双亲委派模型?
如果我们不想打破双亲委派模型,但又不想使用双亲委派模型,就重写ClassLoader类中的findClass()方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。
但是,如果想打破双亲委派模型则需要重写ClassLoader类中的loadClass()方法
6. 自定义类加载器
除了BootstrapClassLoader,其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承ClassLoader。
Java虚拟机类加载器--双亲委派模型相关推荐
- 由源码深入Java类加载器(双亲委派模型)
JVM类加载器 JVM主要有以下几种类加载器: 引导类加载器 主要加载JVM运行核心类库,位于JRE的lib目录下,如rt.jar中的类. 扩展类加载器 主要加载JVM中扩展类,位于JRE的ext目录 ...
- java类加载和双亲委派模型浅说
本文目录 前言 一.类加载器 1.1 类加载机制的基本特征 1.2 类加载的分类 1.3 类加载器 A.启动类加载器(引导类加载器,Bootstrap ClassLoader) B.扩展类加载器(Ex ...
- 类加载器-双亲委派机制
上一篇:类加载器-分类 一.概述 除了根类加载器之外,其他的类加载器都需要有自己的父加载器.从JDK1.2开始,类的加载过程采用双亲委派机制,这种机制能够很好的保护java程序的安全.除了虚拟机自带的 ...
- 类加载器双亲委派模式
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只 ...
- 面向对象回顾(静态变量、类加载机制/双亲委派模型、Object类的方法、类和对象区别)
1. 静态变量存在什么位置? 方法区 2. 类加载机制,双亲委派模型,好处是什么? 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务, ...
- java虚拟机中的双亲委派机制
文章目录 双亲委派机制 工作原理 工作场景 调用过程 三种加载器调用范围 String类加载过程 StringTest类加载过程 双亲委派机制优点 双亲委派机制 Java虚拟机对class文件采用的是 ...
- 类加载器-双亲委派-源码分析1
双亲委派模式 所谓的双亲委派,就是指调用类加载器的 loadClass 方法时,查找类的规则 注意 protected Class<?> loadClass(String name, bo ...
- 类加载器-双亲委派-源码分析2
public class Load5_3 {public static void main(String[] args) throws ClassNotFoundException {Class< ...
- JVM—类加载器和双亲委派模型
关注微信公众号:CodingTechWork,一起工作学习总结. 文章目录 引言 类加载器 类与类加载器关系 类加载器分类 启动类加载器 扩展类加载器 应用程序类加载器 双亲委派模型 介绍 工作流程 ...
- java获取类加载器
获取类加载器的方法: //扩展类加载器MainClassLoader classLoader = MainTest.class.getClassLoader();//表示当前线程的类加载器--应用程序 ...
最新文章
- happens-before俗解
- 关于对Enum的理解
- c#操作html dom元素,C#获取与修改HTML DOM元素信息
- Halcon—Tuple中符号的含义
- MYSQL 编码设置
- git常用命令之log
- 在实际工作中,WPS对比office,谁更强?
- git命令行删除远程文件
- 使用Eclipse Babel语言包汉化eclipse
- python中水量_Python居然还能用于巨大的工程项目!比如三峡发电量估算系统!
- Java接口配置框架magic-api
- 每日学习(Git和Github)
- 台式电脑添加共享计算机,台式电脑怎么设置wifi共享
- 云栖大会 | Apache Spark 3.0 和 Koalas 最新进展
- Python程序员必备——手把手教你配置最漂亮的PyCharm界面
- [模版]尽整些歪门邪道
- 单片机51实现计算器详细代码能自己运行
- 中国海洋大学2009-2010秋季学期c语言期末考试试题,中国海洋大学C语言期末笔试2010年7月A...
- JavaScript 数组塌陷
- Ubuntu18.04启用中文输入法