月薪过万必会的:双亲委托模型
csdh11 2025-04-26 17:30 3 浏览
来源于万猫学社 ,
作者程绪源
类加载器简介
在介绍双亲委托模型之前,先介绍一下类加载器。类加载器通过一个类的全限定名来转换为描述这个类的二进制字节流。
对于任意一个类,被同一个类加载器加载后都是唯一的,但如果被不同加载器加载后,就不是唯一的了。即使是源于同一个Class文件、被同一个JVM加载,只要加载类的加载器不同,那么类就不同。
如何判断类是否相同,可以使用Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果进行判断,也可以使用instanceof关键字进行对象所属关系的判断。
下面我们写一个不同类加载器加载后的类,看一下对instanceof关键字运算有什么影响:
运行结果:
class name: OneMoreStudy
instanceof: false
在运行结果中,第一行可以看出这个对象确实是OneMoreStudy类实例化出来的,但在第二行中instanceof运算结果是false,说明在JVM中存在两个OneMoreStudy类,一个是由系统应用程序类加载器加载的,另一个是由我们自定义的类加载器加载的。虽然都是来自同一个Class文件,在同一个JVM里,但是被不同的类加载器加载后,仍然是两个独立的类。
类加载器的划分
除了像上面例子代码中,我们自己实现的自定义类加载器,还有3种系统提供的类加载器:
- 启动类加载器(Bootstrap ClassLoader):它负责将存放在%JAVA_HOME%\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是JVM识别的类库加载到JVM内存中。它仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载。它是由C++语言实现的,无法被Java程序直接引用。
- 扩展类加载器(Extension ClassLoader):它负责加载%JAVA_HOME%\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。它由sun.misc.Launcher.ExtClassLoader实现,开发者可以直接使用扩展类加载器。
- 应用程序类加载器(Application ClassLoader):它负责加载用户类路径(ClassPath)上所指定的类库。由于它是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它由sun.misc.Launcher.AppClassLoader来实现,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
双亲委托模型
之前提到,对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在JVM中的唯一性。可是有这么多种的类加载器,如何保证一个类在JVM中的唯一性呢?为了解决这个问题,双亲委托模型(Parents Delegation Model)应运而生,它就是下图所展示的类加载器之间的层次关系:
除了顶层的启动类加载器外,其余的类加载器都必须有自己的父类加载器。类加载器之间的父子关系,一般不会以继承的关系来实现,而是都使用组合关系来复用父类加载器。
类加载器收到类加载的请求后,它不会首先自己去尝试加载这个类,而是把这个请求委派给父类加载器去尝试加载。每一个类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中。只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。这样就保证了类在JVM中的唯一性,也保证了Java程序稳定运作。
实现双亲委派模型的代码都集中在java.lang.ClassLoader的loadClass()方法之中,如下:
破坏双亲委派模型
双亲委派模型并不是一个强制性的约束模型,而是Java设计者们推荐给开发者们的类加载器实现方式。大部分的类加载器都遵循这个模型,但也有例外的情况,比如下面这三种情况:
重写ClassLoader的loadClass()方法
在上面例子代码中,就是重写了ClassLoader的loadClass()方法,破坏了双亲委派模型,产生了不唯一的类。所以,不提倡开发人员覆盖loadClass()方法,而应当把自己的类加载逻辑写到findClass()方法中,在loadClass()方法的逻辑里如果父类加载失败,则会调用自己的findClass()方法来完成加载,这样就可以保证新写出来的类加载器是符合双亲委派模型。
SPI(服务提供者接口)
Java提供了很多SPI(Service Provider Interface,服务提供者接口),允许第三方为这些接口提供实现,常见的SPI有JDBC、JNDI、JCE、JAXB和JBI等。
SPI的接口由Java核心库来提供,而这些SPI的实现代码则是作为Java应用所依赖的jar包被包含进类路径(ClassPath)里。SPI接口中的代码经常需要加载具体的实现类。那么问题来了,SPI的接口是Java核心库的一部分,是由启动类加载器来加载的;SPI的实现类是由系统类加载器来加载的。引导类加载器是无法找到SPI的实现类的,因为依照双亲委派模型,启动类加载器无法委派系统类加载器来加载类。
这时候就会使用线程上下文类加载器(Thread Context ClassLoader),在JVM中会把当前线程的类加载器加载不到的类交给线程上下文类加载器来加载,直接使用Thread.currentThread().getContextClassLoader()来获得,默认返回的就是应用程序类加载器,也可以通过java.lang.Thread类的setContextClassLoader()方法进行设置。
而线程上下文类加载器破坏了双亲委派模型,也就是父类加载器请求子类加载器去完成类加载的动作,但为了实现功能,这也是一种巧妙的实现方式。
OSGi(开放服务网关协议)
OSGi(Open Service Gateway Initiative,开放服务网关协议)技术是面向Java动态化模块化系统模型,程序模块(称为Bundle)无需重新引导可以被远程安装、启动、升级和卸载。实现程序模块热部署的关键则是它自定义的类加载器机制的实现。
在OSGi中,类加载器不再是双亲委派模型中的树状结构,而是一个较为复杂的网状结构,类加载的规则简要介绍如下:
- 若类属于java.*包,则将加载请求委托给父加载器
- 若类定义在启动委托列表(org.osgi.framework.bootdelegation)中,则将加载请求委托给父加载器
- 若类属于在Import-Package中定义的包,则框架通过ClassLoader依赖关系图找到导出此包的Bundle的ClassLoader,并将加载请求委托给此ClassLoader
- 若类资源属于在Require-Bundle中定义的Bundle,则框架通过ClassLoader依赖关系图找到此Bundle的ClassLoader,将加载请求委托给此ClassLoader
- Bundle搜索自己的类资源( 包括Bundle-Classpath里面定义的类路径和属于Bundle的Fragment的类资源)
- 若类在DynamicImport-Package中定义,则开始尝试在运行环境中寻找符合条件的Bundle
如果在经过上面一系列步骤后,仍然没有正确地加载到类资源,则会向外抛出类未发现异常。
总结
类加载器通过一个类的全限定名来转换为描述这个类的二进制字节流,可划分为启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器。在双亲委托模型中,将上述各种类加载器组成一系列的父子关系,子类加载器先把类加载请求委派给父类加载器去尝试加载,父类加载器无法加载时子类加载器才自己尝试加载,这样保证了类在JVM中的唯一性。不过,也不遵循双亲委托模型的情况,比如:重写ClassLoader的loadClass()方法、SPI(服务提供者接口)、OSGi(开放服务网关协议)。
相关推荐
- 一文了解NTFS和FAT32的真正区别
-
FAT32文件系统是在win98时代最常用的文件系统。而NTFS文件系统在winxp的时代开始流行,一直持续到现在。它们之间有什么区别呢?主要有四个方面的区别。1、兼容性FAT32文件系统是在1997...
- 海韵教育丨系统文件和系统文件夹解析
-
系统文件夹...
- DOSBox 使用指南:在现代电脑上重温经典 DOS 游戏
-
想在Windows、Mac或Linux上玩经典的DOS游戏?DOSBox让你轻松实现!DOS时代的经典游戏,比如《毁灭战士(Doom)》《波斯王子(PrinceofPersia)》...
- Windows系统CMD-DOS命令大全及CMD命令与运行命令的区别
-
Windows系统CMD-DOS命令和开始→运行(win+R)命令的区别...
- 如何批量修复dll动态链接库文件
-
系统安装文件夹中存在以dll为后缀的动态链接库文件,它们为系统和软件提供底层支持。有时安装软件后,可能会遇到无法连接dll文件的提示。如何修复这些问题?下面将为大家介绍dll动态链接库的修复方法,跟随...
- Dos命令大全
-
1.#查看当前所在目录文件dir2.#切换目录cdchangedirector3.#返回上一级cd..4.#清除屏幕cls(clearscreen)5.#退出终端exit6.#查看电...
- dos命令net share图文教程,创建删除显示网络计算机电脑共享资源
-
大家好,我是老盖,首先感谢观看本文,本篇文章做的有视频,视频讲述的比较详细,也可以看我发布的视频。今天我们学习net命令中的share这个命令,它这个命令可以创建删除电脑的共享资源,输入命令nets...
- 硬盘坏道修复
-
硬盘出现坏道是致命故障,若坏道频繁发生,可能表明硬盘寿命将尽。此时应警惕,妥善保存数据,随时准备更换新硬盘。硬盘坏道分为物理坏道和逻辑坏道两类,需区别对待处理。1、硬盘出现坏道后,不仅部分扇区无法使...
- 经典重温:Windows 95系统
-
2014-11-2605:03:00作者:李英杰科技在快速发展,桌面操作系统也在不断更新换代。作为有史以来最成功的操作系统之一,Windows95相比之前的Win3.x在界面和功能上实现了巨大...
- 电脑键盘各键名称及功能
-
了解电脑操作快捷键,高效使用电脑,提高工作效率。电脑键盘功能示意图:各个区中各键名称:各键功能:PageDown:向下翻页键。Page,页的意思,Down,向下的意思。和Pageup键相呼应。笔记本键...
- DOS命令-出错提示与对策
-
[英文提示]Generalfailure[中 文]通用失败[原 因]DOS不能判断错误的原因,一般是因为驱动器中的磁盘未格式化,或格式化成非DOS系统。[对 策]应该重新格式化磁...
- EXCEL一篇搞定,根据当天日期批量创建数百个文件夹
-
我是做销售统计的,每天都需要收集门店的日报,每天都需要针对每个门店创建一个文件夹第一层是日期,然后是门店名称对应的文件夹我每天都要一个一个创建,现在门店多了,创建都花了半天时间,有简单的方法吗?我太难...
- Win10彻底删除Java1.8流程
-
一定要先将环境变量删除再卸载jdk,最后删除注册表...
- 批处理命令——玩转目录之dir
-
我在前面系列的批处理文章中曾提到过dir这个dos命令,它是显示目录或文件的一个命令,那么它详细的用途是什么呢,我们使用它时又需要注意什么呢?上面是dir/?输出的内容。其实主要用到的参数也就几个。...
- 如何彻底删除电脑文件?怎么防止删除文件恢复?
-
数据安全可以说是信息时代的一大安全隐患,如果我们打算把电脑和硬盘变卖或转赠他人,那么彻底删除电脑文件和防止删除的文件被恢复是非常重要的操作,下面分别予以说明。一、如何彻底删除电脑文件...
- 一周热门
- 最近发表
- 标签列表
-
- mydisktest_v298 (34)
- document.appendchild (35)
- 头像打包下载 (61)
- acmecadconverter_8.52绿色版 (39)
- word文档批量处理大师破解版 (36)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- parsevideo (33)
- 个人网站源码 (37)
- centos7.4下载 (33)
- mysql 查询今天的数据 (34)
- intouch2014r2sp1永久授权 (36)
- 先锋影音源资2019 (35)
- jdk1.8.0_191下载 (33)
- axure9注册码 (33)
- pts/1 (33)
- spire.pdf 破解版 (35)
- shiro jwt (35)
- sklearn中文手册pdf (35)
- itextsharp使用手册 (33)
- 凯立德2012夏季版懒人包 (34)
- 冒险岛代码查询器 (34)
- 128*128png图片 (34)
- jdk1.8.0_131下载 (34)
- dos 删除目录下所有子目录及文件 (36)