ClassLoader 隔离性的基石是namespace,证明给你看

news/2024/5/19 22:42:28/文章来源:https://blog.csdn.net/m0_71777195/article/details/128350645

一、背景

朋友:在我知识体系中ClassLoader的双亲委派机制是流畅丝滑的,可是看到通过委派执行类加载来保障这种分治能力,进而达到了类资源的隔离性突然就感觉有点陌生和排斥呢?

我:类的命名空间有了解嘛?

朋友:你是说package嘛?

我:我说的是ClassLoader中的 nameSpace

朋友:啥玩意儿?

本篇是对ClassLoader中的namespace做个直观的介绍和验证。这个知识点笔者个人认为很重要,多次帮助笔者解决日常工作中遇到的疑难杂症,如果你尚未认真研究过ClassLoader,但懵懂的认知让你觉得这个应该很简单,那请看下图,若看不懂则表明你可能并不了解ClassLoader中得一些关键逻辑;不贩卖焦虑,不感兴趣则忽略,知道个大概即可,不会它并不影响你做一个优秀的程序员。

namespace(图片来自网络).png

二、Classloader的分治和委派机制

上下文同步,已了解这部分的读者朋友可直接跳过,进过第三小节。

ClassLoader 是个抽象类,其子类 UrlClassLoader 引入 URL 资源概念,以此方式来约束自己只加载 URL 覆盖范围内的类文件;ExtClassLoaderAppClassLoader 都是 UrlClassLoader 的子类,各自分管的资源路径不同,即给定的 URL 不同则管辖范围不同,并通过委派执行类加载来保障这种分治能力,进而达到了类资源的隔离性。

上图是标准的委派机制,总结为2个方面:

  1. 父加载器能加载 父加载器来加载:

    • 自己在加载资源之前,先让父类加载器去加载。父类再找其父类,直到BootStrapClassLoader(它没有父类加载器)。
    • 保证了等级越高,加载的优先权越高
  2. 父加载器不加载 我就来加载(findClass);我加载不了的子加载器来加载:

    • 若父类加载器没有加载成功,才逐级下放这个加载权。
    • 子类加载器不能加载父类加载器能加载的类,如 java.lang.String ,即使用户自己编造一份这个类型,启动类加载器优先将 java.lang.String 加载成功后,应用类加载器就不会再加载用户自己编造的。

下图描述了 SkyWalking Agent 通过自定义的类加载器AgentClassLoader 加载插件中的类,不会对宿主应用中的类产生污染。

三、namespace是什么?

每个类加载器都对应一个namespace,汉化叫命名空间(我个人其实更喜欢汉化为名字空间),命名空间由该加载器及所有父类加载器所加载的类组成。这样的介绍很抽象,网络资料中也多是这么几句话,我会从更多的细粒度视角带您进一步了解它。

3.1 同一个命名空间中,类只加载一份

比如AppClassLoader加载程序中编写的类。无论加载多少次,只要是被AppClassLoader加载的,其Class信息的hashcode都是相同的。

3.2 子加载器可见父加载器加载的类

这个更容易举例,核心类库的类由BootStrapClassLoder 加载的,比如String;由AppClassLoader所加载的类,都能使用String对吧?

3.3 父加载器不可见子加载器所加载的类

SPI技术的诞生也是这个原因,什么是SPI:程序运行过程中要用到的类,通过当前类加载器自动加载,加载不到(不在当前类加载器的类资源管辖范围),如果要使用这个类,必须指定一个能够加载这个类的加载器去加载,而怎么获取这个加载器是个问题。
程序都是在线程中执行,那么从线程的上下文中去拿最合理,所以就诞生了线程上下文类加载器,这中场景下加载器就得采用非自动加载,即通过 forName 或者 loadClass 的方式去加载类。

下边通过示例+科技来验证加载不到的情况

示例中有Parent类,Son类。Parent类中有个getSon方法中,会使用到Son类。 编译后,在classpath下,把Son类移到自定义子加载器的资源目录中,让AppClassLoader无法加载。达到我们的运行环境要求:

  1. ParentAppClassLoader加载
  2. Son由自定义的子加载器加载.
  3. 调用ParentgetSon方法的时候要new Son(),这样会触发Son类的加载,但是加载不到Son类,报错信息为:java.lang.NoClassDefFoundError: com/rock/Son
public class Parent {private Object son;public Object getSon(){return new Son();}public Object setSon(Object son){this.son = son;return this.son;}
}  
public class Son {
}
复制代码
/*** 父加载器加载不了,子加载器所加载的类,* 父加载器加载Parent* 子加载器加载son* Parent#getSon 方法里 new Son()对象.//报错,找不到Son的类定义.*/@Testpublic void testParentCanntFindSon(){CustomClassLoader01 customClassLoader01 = new CustomClassLoader01(ClassLoader.getSystemClassLoader());try {Class<?> classParent = customClassLoader01.loadClass("com.rock.Parent");System.out.println("classParent:" + classParent.getClassLoader());Class<?> classSon = customClassLoader01.loadClass("com.rock.Son");System.out.println("classSon:" + classSon.getClassLoader());Object objParent = classParent.newInstance();Object objSon = classSon.newInstance();Method setSon = classParent.getMethod("setSon",Object.class);Object resultSon = setSon.invoke(objParent, objSon);System.out.println(resultSon.getClass());System.out.println(resultSon.getClass().getClassLoader());try {Method getSon = classParent.getMethod("getSon");Object invoke = getSon.invoke(objParent);System.out.println(invoke.getClass().getClassLoader());}catch (Exception exp){//java.lang.NoClassDefFoundError: com/rock/Sonexp.printStackTrace();}}catch (Exception exp){exp.printStackTrace();}}
复制代码

3.4 不同命名空间的类互相不可见

这个特征也通过实例来验证一下,自定义类加载器 new 出来两个实例,每个实例各自加载一次Man类,通过newInstance方式实例化出两个对象,对象之间互相调用setFather赋值就会报错。即a空间的不识别b空间的类,即使全限定名相同也不识别。这种特性所导致的坑你踩到过嘛?

public class Man {private Man father;public void setFather(Object obj){father = (Man)obj;}
}
复制代码
 @Testpublic void testSifferentNamespaceClass(){CustomClassLoader01 customClassLoader01 = new CustomClassLoader01(ClassLoader.getSystemClassLoader());CustomClassLoader01 customClassLoader02 = new CustomClassLoader01(ClassLoader.getSystemClassLoader());try {Class<?> aClass1 = customClassLoader01.loadClass("com.rock.Man");System.out.println("class1 : " + aClass1.getClassLoader());System.out.println("class1 : " + aClass1.);Class<?> aClass2 = customClassLoader02.loadClass("com.rock.Man");System.out.println("class2 : " + aClass1.getClassLoader());System.out.println("class2 : " + aClass2);Object man1 = aClass1.newInstance();Object man2 = aClass2.newInstance();Method setFather = aClass1.getMethod("setFather", Object.class);setFather.invoke(man1,man2);}catch (Exception exp){exp.printStackTrace();}}
复制代码
class1 : com.rock.classLoader.CustomClassLoader01@1f28c152
class1 : 2006034581
class2 : com.rock.classLoader.CustomClassLoader01@1f28c152
class2 : 488044861
...
Caused by: java.lang.ClassCastException: com.rock.Man cannot be cast to com.rock.Manat com.rock.Man.setFather(Man.java:6)... 27 more

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优秀的后端应该有哪些开发习惯?

见识过各种各样的代码,优秀的、垃圾的、不堪入目的、看了想跑路的等等,所以这篇文章记录一下一个优秀的后端 Java 开发应该有哪些好的开发习惯。 拆分合理的目录结构 受传统的 MVC 模式影响,传统做法大多是几个固定的文件夹 controller、service、mapper、entity,然后无限…

超越nnFormer!UNETR++:高效准确的3D医学图像分割

UNETR: Delving into Efficient and Accurate 3D Medical Image Segmentation 论文链接&#xff1a; https://arxiv.org/abs/2212.04497 代码链接&#xff1a; https://github.com/Amshaker/unetr_plus_plus 导读 这篇论文主要讲述了一种名为 UNETR 的 3D 医学图像分割方法&…

Spring MVC【创建与使用】

Spring MVC【创建与使用】&#x1f34e;一.Spring MVC介绍&#x1f352;1.1 什么是SpringMVC?&#x1f352;1.2 MVC 定义&#x1f352;1.3 Spring MVC 与 MVC 的区别&#x1f352;1.4 Spring MVC的基本功能&#x1f34e;二. Spring MVC项目的创建&#x1f352;2.1 Spring MVC …

[附源码]计算机毕业设计PythonQ宝商城(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

WebService基于Baidu OCR和Map API的导航服务

哈尔滨工业大学国家示范性软件学院 《面向服务的软件系统》大作业 项目题目&#xff1a; 基于OCR和地图API的路牌定位与导航服务 项目组成员&#xff1a; 姓名 学号 李启明 120L021920 完成日期&#xff1a; 2022年 12 月 15 日 1.选题 1.1 作业…

Spring Boot热部署配置

⭐️前言⭐️ 在我们进行Spring Boot项目的编写过程中&#xff0c;会有局部的代码&#xff0c;发生一些变动&#xff0c;这时候&#xff0c;我们只有将项目重启&#xff0c;发生变动的代码才能够生效&#xff0c;为了解决这个问题&#xff0c;我们可以设置Spring Boot热部署&a…

【财务】FMS财务管理系统---应收管理

笔者前面介绍了FMS财务管理系统相关逻辑结构&#xff0c;本篇文章继续对应收管理进行了系统的介绍&#xff0c;希望通过此文能够加深你对FMS财务管理系统的认识。 上一篇主要介绍了财务进销存系统的数据流与模块组成&#xff0c;知道了FMS系统中数据的来源并从系统结构上说明了…

Wireshark 实验

本部分按照数据链路层、网络层、传输层以及应用层进行分类&#xff0c;共有 10 个实验。需要使用协议分析软件 Wireshark 进行&#xff0c;请根据简介部分自行下载安装。 准备 请自行查找或使用如下参考资料&#xff0c;了解 Wireshark 的基本使用&#xff1a; 选择对哪块网…

Linux——linux面试题

cat a.txt | cut -d "/" -f 3 | sort | uniq -c |sort -nrgrep ESTABLISHED | awk -F " " {print $5} |cut -d ":" -f 1 | sort |uniq -c | sort -nr找回mysql的root用户的密码 首先&#xff0c;进入到/etc/my.cnf&#xff0c;插入一句skip-gra…

Linux——虚拟机安装Linux系统

实验1-2 虚拟机安装Linux系统 VMware 9.0 虚拟机Linux镜像ISO文件相关工具可以在这里边找到 http://pan.baidu.com/s/1ntA18FJ 或者请自行下载使用 创建新的虚拟机&#xff0c;如下图&#xff1a; 下一步&#xff1a;选择安装配置类型为“典型”如下图&#xff1a; 下一步&…

大厂频频裁员,0基础转行做IT是不是已经晚了

现在转行做程序员是不是已经晚了 转行不会晚&#xff0c;晚的是你数不清的犹豫 对于二十来岁刚毕业或者毕业没几年的人来说&#xff0c;经历过社会的“摧残”&#xff0c;面对着一眼能够望到头的工作&#xff0c;拿着也不太高的工资&#xff0c;总是会去寻求一些改变与其每天…

net/http 库的客户端实现(上)

前言 Go语言标准库 net/http 是一个非常强大的标准库&#xff0c;使得构建 HTTP 请求和编写 Web 服务器的工作变得非常简单。 我们来看看是他是如何实现客户端和服务端的。 使用示例 假设本地有一个GET方法的HTTP接口&#xff0c;响应 Hello World&#xff01; 使用 net/ht…

密西根大学张阳实验室郑伟博士在CASP15蛋白质结构预测大赛中斩获多项冠军

简报&#xff1a;在有着蛋白质结构预测领域奥林匹克竞赛之称的最新一届CASP比赛中&#xff08;CASP15&#xff09;&#xff0c;密西根大学张阳教授和Peter Freddolino教授实验室的郑伟博士在多个比赛项目中获得冠军。其中D-I-TASSER算法&#xff08;参赛名&#xff1a;“UM-TBM…

python中调用命令行执行外部程序

&#x1f31e;欢迎来到python的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f320;本阶段属于练气阶段&#xff0c;希望各位仙友顺利完成…

Web前端大作业——城旅游景点介绍(HTML+CSS+JavaScript) html旅游网站设计与实现

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

【YOLOv7-环境搭建】PyTorch安装后输出版本显示No module named ‘Torch’的解决方法

可能一&#xff1a;PyCharm环境导入错误 配置的解释器&#xff0c;必须为所创建的虚拟环境下的python.exe文件&#xff0c;别的路径下的python.exe文件不好使&#xff01;&#xff01; 解决方法&#xff1a;根据【YOLOv7-环境搭建③】PyCharm安装和环境、解释器配置文中配置解…

spring @annotation 注解

切入点函数&#xff1a;用于执行切入点函数 1.execution 1.最为重要的切入点函数&#xff0c;功能最全 2.可以执行方法切入点表达式&#xff0c;可以执行类切入点表达式&#xff0c;可以执行包切入点表达式 弊端&#xff1a;书写比较麻烦 2.args 1.作用&#xff1a;主要用…

零基础怎么学Python编程,新手常犯哪些错误?

Python是人工智能时代最佳的编程语言&#xff0c;入门简单、功能强大&#xff0c;深获初学者的喜爱。 很多零基础学习Python开发的人都会忽视一些小细节&#xff0c;进而导致整个程序出现错误。下面就给大家介绍一下Python开发者常犯的几个错误。 1、错误的使用变量。 在Pyt…

三面美团测开岗,HR 现场直接发 offer,他是横着走出来的

前情提要 这是一个发生在我朋友身上的真实事情&#xff1a; 这里就叫他程序员 Y 吧。 程序员 Y 工作不到两年&#xff0c;周末在朋友圈发了个喜报&#xff0c;准备入职美团。 之后&#xff0c;我就带着祝福跟 Y 聊了许久&#xff0c;聊天的内容就是具体了解一下他面试的过程…

行为树 --- [7] BehaviorTree.CPP 4.x版本的编译及使用

根据BehaviorTree.CPP的官方介绍&#xff0c;3.x版本已经不再维护了&#xff0c;建议使用4.x版本&#xff0c; 4.x版本和3.x版本的区别可以看这里 — https://www.behaviortree.dev/migration 本文介绍4.x版本的编译及使用&#xff0c;环境是Debian 10.5&#xff0c;编译器是…