如果你还不了解双亲委派模型,来看看这篇吧

news2024/11/22 13:41:33

文章首发于【Java天堂】,跟随我探索Java进阶之路!

类与类加载器

类是由它的类加载器加载进虚拟机中的,在同一个Java虚拟机中,对于同一个Class文件,如果采用不同的类加载器,得到的是不相等的类,对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。

public class ClassLoadTest {

    public static void main(String[] args) throws Exception {
        ClassLoader myClassLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                try {
                    String className = name.substring(name.lastIndexOf(".") + 1) + ".class";
                    InputStream is = getClass().getResourceAsStream(className);
                    if (is == null) {
                        return super.loadClass(name);
                    }
                    byte[] b  = new byte[is.available()];
                    is.read(b);
                    return defineClass(name,b,0,b.length);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }
        };

        Object obj = myClassLoader.loadClass("org.example.ClassLoadTest").newInstance();
        System.out.println(obj.getClass());
        System.out.println(obj instanceof  org.example.ClassLoadTest);
    }

}

上面的例子中,我自己创建了一个简单的类加载器myClassLoad,然后我使用这个类加载器加载ClassLoadTest,最后使用instanceof来检测得到false

class org.example.ClassLoadTest
false

这是因为Java虚拟机中存在两个ClassLoadTest类,一个是由虚拟机的应用程序类加载器加载的,另外一个是由myClassLoad加载进来的。虽然他们都来自于同一个Class文件,但在Java虚拟机中是两个独立的类

双亲委派模型

站在Java虚拟机的视角,类加载器分为:

  • 启动类加载器(Bootstrap ClassLoader),由C++语言实现,是虚拟机自身的一部分
  • 其他所有类的加载器,由Java语言实现,独立存在于Java虚拟机外部

站在开发人员的视角,类加载器分为:

  • 启动类加载器(Bootstrap ClassLoader),负责加载存放在 \lib目录,或者被-Xbootclasspath参数所指定的路径中存放的,而且是Java虚拟机能够识别的(按照文件名识别,如rt.jar、tools.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机的内存中
  • 扩展类加载器(Extension Class Loader),负责加载 \lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库
  • 应用程序类加载器(Application Class Loader),负责加载用户类路径(ClassPath)上所有的类库,开发者同样可以直接在代码中使用这个类加载器。如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器

pkmLnij.md.png

如上图所示,除了用户自定义类加载器外,默认是由三种类加载器配合完成类的加载。

上图的关系称为“双亲委派模型”,双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。不过这里类加载器之间的父子关系一般不是以继承(Inheritance)的关系来实现的,而是通常使用组合(Composition)关系来复用父加载器的代码

双亲委派模型的工作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载

双亲委派模型的好外

  • 避免类的重复加载: 如果每个类加载器都独立加载类,那么相同的类可能会被多次加载,导致内存中存在多个相同类的副本,这显然是不必要的资源浪费。双亲委派模型确保了类的唯一性,一旦某个类加载器的父加载器已经加载了一个类,子加载器就不会再加载同一个类
  • 保证核心类库的一致性: Java的核心类库(如java.lang.String)位于Bootstrap ClassLoader中。如果允许自底向上的加载方式,用户定义的类加载器可能会尝试加载这些核心类,这可能导致安全问题和版本冲突。双亲委派模型确保了这些基础类只由启动类加载器加载,保证了系统类的统一性和安全性
  • 隔离应用程序类和系统类: 不同的应用程序可能定义了相同包和类名的类,但它们应该互不影响。双亲委派模型使得系统类(如java.*包中的类)与应用程序类(用户自定义的类)得以区分,防止应用程序随意覆盖系统类
  • 维护Java的类加载生态: 这种机制使得第三方类库的加载更加有序,开发者可以自定义类加载器来加载特定的类,而不需要担心与系统类发生冲突,因为系统类总是会被先加载

破坏双亲委派模型的场景

双亲委派模型并不是一个具有强制性约束的模型,而是Java设计者推荐给开发者们的类加载器实现方式。在Java的世界中大部分的类加载器都遵循这个模型,但也有例外的情况

场景1:发生在双亲委派模型出现之前

由于双亲委派模型在JDK 1.2之后才被引入,但是类加载器的概念和抽象类java.lang.ClassLoader则在Java的第一个版本中就已经存在,面对已经存在的用户自定义类加载器的代码,Java设计者们引入双亲委派模型时不得不做出一些妥协,为了兼容这些已有代码,无法再以技术手段避免loadClass()被子类覆盖的可能性,只能在JDK 1.2之后的java.lang.ClassLoader中添加一个新的protected方法findClass(),并引导用户编写的类加载逻辑时尽可能去重写这个方法,而不是在loadClass()中编写代码

场景2:模型自身的缺陷导致的

JNDI现在已经是Java的标准服务,它的代码由启动类加载器来完成加载(在JDK 1.3时加入到rt.jar的),肯定属于Java中很基础的类型了。但JNDI存在的目的就是对资源进行查找和集中管理,它需要调用由其他厂商实现并部署在应用程序的ClassPath下的JNDI服务提供者接口(Service Provider Interface,SPI)的代码,现在问题来了,启动类加载器是绝不可能认识、加载这些代码的,那该怎么办?

为了解决这个困境,Java的设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContext-ClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器

有了线程上下文类加载器,JNDI服务使用这个线程上下文类加载器去加载所需的SPI服务代码,这是一种父类加载器去请求子类加载器完成类加载的行为,这种行为实际上是打通了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型的一般性原则,但也是无可奈何的事情

虽然上述两个场景破坏了双亲委派模型,但只要有明确的目的和充分的理由,突破旧有原则也算是一种创新

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s二进制部署--多master、负载均衡、高可用

目录 1、环境准备 1.1 服务器配置 1.2 master02 节点部署 2、负载均衡部署 2.1 下载nginx 2.2 修改nginx配置文件 2.3 启动nginx 2.3.1 检查配置文件语法 2.3.2 启动nginx服务&#xff0c;查看已监听6443端口 3. 部署keepalived服务(nginx主机&#xff0c;以nginx01为…

十一.吊打面试官系列-JVM优化-深入JVM类加载机制

前言 从本篇文章开始我们来探讨JVM相关的知识&#xff0c;内容附带JVM的启动&#xff0c;JVM内存模型&#xff0c;JVM垃圾回收机制&#xff0c;JVM参数调优等&#xff0c;跟着文章一步一步走相信你对JVM会有一个不一样的认识&#xff0c;如果觉得文章对你有所帮助请给个好评吧…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt 驾校管理系统 设计与实现

一.项目介绍 系统角色&#xff1a;管理员、驾校教练、学员 管理员&#xff1a; 个人中心&#xff1a;修改密码以及个人信息修改 学员管理&#xff1a;维护学员信息&#xff0c;维护学员成绩信息 驾校教练管理&#xff1a;驾校教练信息的维护 驾校车辆管理&…

水离子雾化壁炉与会所房间的氛围搭配

水离子雾化壁炉在会所房间的氛围搭配可以为房间增添舒适、温馨和现代感&#xff0c;以下是一些建议&#xff1a; 主题定位&#xff1a; 根据会所房间的主题和定位选择合适的水离子雾化壁炉款式和设计风格。可以是现代简约、欧式古典或是豪华奢华&#xff0c;确保与房间整体风格…

Java基础学习笔记二

Java基础学习笔记二 6 File1.File类1.1File类概述和构造方法【应用】1.2File类创建功能【应用】1.3File类判断和获取功能【应用】1.4File类删除功能【应用】 2.递归1递归【应用】2递归求阶乘【应用】3递归遍历目录【应用】 3.IO流1 IO流概述和分类【理解】2字节流写数据【应用】…

HL7协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.介绍2.传输协议规范2.1. MLLP2.1.1. 数据头定义2.1.2. 转义字符集 2.2. 规范说明2.3. 消息格式说明 3.HL7结构介绍3.1. 患者建档&#xff08;ADT^A28&#xff09;…

AI应用之智能体介绍

AI应用之智能体介绍 一、LLM介绍二、智能客服应用1&#xff0c;阿里智能能话机器人2&#xff0c;华为对话机器人3&#xff0c;公司基于讯飞知识库和讯飞大模型的智能客服 三、大模型应用平台介绍1&#xff0c;fastgpt2&#xff0c;毕昇3&#xff0c; 字节海外版&#xff08;科学…

学习Nginx(二):版本介绍和安装

版本 Nginx官方定义了Mainline、Stable、Legacy三种版本。 1. Mainline version&#xff08;主线版本&#xff09; 该版本包含最新的功能和bug修复&#xff0c;被视为开发版&#xff0c;即正在活跃开发中的版本。其版本号通常为单数&#xff0c;例如1.25.5。这个版本的更新较快…

Nvidia Jetson编译安装Opencv With CUDA,完善GSTREAMER功能

简介 Nvidia Jetson 官方刷机流程结束以后&#xff0c;虽然安装了opencv&#xff0c;但是此版本是CPU版本&#xff0c;并且不包含Cpp版本。如果想要完整的OpenCV支持&#xff0c;需要从源码编译。本文介绍如何下载编译&#xff0c;并安装OPENCV库&#xff0c;并获得完整的CUDA…

必应bing广告开户费用介绍,必应搜索广告推广开户服务!

微软必应Bing搜索引擎广告成为了企业提升品牌知名度与市场份额的有效途径之一&#xff0c;作为全球第二大搜索引擎&#xff0c;在中国市场正逐步展现出其独特的广告价值与潜力。对于希望拓展在线市场的中国企业而言&#xff0c;通过云衔科技开启必应Bing国内广告推广之旅&#…

谷歌外贸seo优化怎么做?

一般有两种选择&#xff0c;在大型电商平台开展业务&#xff0c;如亚马逊&#xff0c;阿里巴巴等平台&#xff0c;也可以选择搭建自己的独立站 选择在大型电商平台可以方便迅速建立起自己的商铺&#xff0c;不需要考虑太多交易&#xff0c;支付&#xff0c;物流等方面的问题&am…

2024.05.14 Diffusion 代码学习笔记

配环境 我个人用的是Geowizard的环境&#xff1a;https://github.com/fuxiao0719/GeoWizard。 出于方便考虑&#xff0c;用的pytorch官方的docker容器&#xff0c;因此python版本&#xff08;3.10&#xff09;和原作者&#xff08;3.9&#xff09;不同&#xff0c;其余都是一…

Java小游戏之汤姆猫

背景&#xff1a; 博主写过羊了个羊小游戏&#xff0c;客户觉得羊了个羊同学写过了&#xff0c;想换一个&#xff0c;于是笔者想到了汤姆猫。就是那个以前在苹果手机上的猫。 过程&#xff1a; 初始会有一个猫的图片展示&#xff0c;然后你点击按钮&#xff0c;猫会有不同动作…

力扣刷题 day2

快乐数 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09;   图: java // 快乐数 --> 19 > 1^2 9 ^2 82 > 82 > 8 ^ 2 2 ^ 2 ......public boolean isHappy(int n) {// 使用快慢指针int slow n, fast getSum(n);while (slow ! fast) {slow getSum(slo…

【Day3:JAVA运算符、方法的介绍】

目录 1、运算符1.1 赋值运算符1.2 比较运算符1.3 逻辑运算符1.3.1 逻辑运算符概述1.3.2 逻辑运算符分类1.3.3 短路的逻辑运算符 1.4 三元运算符1.5 运算符优先级 2、方法2.1 方法介绍2.2 方法的定义和调用格式2.2.1 方法的调用2.2.2 带参数方法的调用2.2.3 带返回值方法的调用2…

Zookeeper and RPC dubbo

javaguide zookeeper面试题 Zookeeper 啥是Zookeeper干啥的 ZooKeeper 可以被用作注册中心、分布式锁&#xff1b; ZooKeeper 是 Hadoop 生态系统的一员&#xff1b; 构建 ZooKeeper 集群的时候&#xff0c;使用的服务器最好是奇数台。 启动ZK 下载安装解压 不过多赘述 我的…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.7讲 GPIO中断实验-编写按键中断驱动

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

luceda ipkiss教程 66:金属线的钝角转弯

案例分享&#xff1a;金属线的135度转弯&#xff1a; 所有代码如下&#xff1a; from si_fab import all as pdk import ipkiss3.all as i3 from ipkiss.geometry.shape_modifier import __ShapeModifierAutoOpenClosed__ from numpy import sqrtclass ShapeManhattanStub(__…

使用Rufus制作Ubuntu启动盘(windows同理)

问题 想要做系统&#xff0c;首先需要做启动盘&#xff0c;使用Rufus做启动盘操作简单。 解决 1.下载Rufus 这个软件免费的一搜便是&#xff0c;这里下载&#xff1a;Rufus - 轻松创建 USB 启动盘。下载完成后即点即用1无需安装。 打开 2.下载Ubuntu镜像 下载地址&#xff…

Flowable配置多数据源以及指定schema

异常反馈 如有问题可通过微信公众号“假装正经的程序员”反馈 为什么要多源 在项目的实际开发过程中通常会有两种常见的使用Flowable的方式&#xff0c;一种是以独立的服务提供工作流的能力&#xff0c;另一种是以Jar包的形式进行内部集成。 这两种方式各有利弊&#xff0c;…