基于SPI机制和DataX插件热加载破坏双亲委派的思考

2023-10-28

在开始阅读之前请先思考以下两个问题,并希望您能再接下来的文章中找到答案

1. 如果我自己实现了一个新的java.lang.String类,并通过UrlClassLoader加载使用该类,能否覆盖JDK中的  java.lang.String ?

2. 如果问题1的回答是不能,那用什么方式能做到覆盖JDK中的java.lang.String么?

一、双亲委派

                                         å亲å§æ´¾å¾

熟悉java类加载机制的一定都知道双亲委派,双亲委派模式的工作原理的是;如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。至于双亲委派的实现原理网上有很多文章可以参考,不是本文的重点,因此不再赘述。

二、破坏双亲委派

WHY AND HOW

1.父类加载器需委托子类加载器加载class文件

受到加载范围的限制,父类加载器无法加载到需要的文件,以Driver接口为例,由于Driver接口定义在jdk当中的,而其实现由各个数据库的服务商来提供,比如mysql的就写了MYSQL CONNECTOR,那么问题就来了,DriverManager(也由jdk提供)要加载各个实现了Driver接口的实现类,然后进行管理,但是DriverManager由启动类加载器加载,只能加载JAVA_HOME的lib下文件,而其实现是由服务商提供的,由系统类加载器加载,这个时候就需要破坏了双亲委派, 启动类加载器来委托子类加载器来加载Driver实现。这就是著名的SPI(SERVICE PROVIDER INTERFACE)机制,其基本概念和运用可参考以JDBC为例谈双亲委派模型的破坏

Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。其基本特点就是,父类提供接口,子类负责实现,父类接口通过配置文件中的实现类的全限定名确定具体的实现,并通过线程上下文加载器接在实现类,最终执行子类的方法实现。概括其逻辑为:加载类=》委托父类加载器加载=》父类加载器通过配置文件找到实现类并获取线程上下文加载器=》加载实现类=》返回实现类实例List

2.实现插件热插拔

DataX是一款热门的数据同步框架,可以将不同数据源的同步抽象为从源头数据源读取数据的Reader插件,以及向目标端写入数据的Writer插件,理论上DataX框架可以支持任意数据源类型的数据同步工作。为了支持对插件化的热插拔,DataX继承UrlClassLoader实现了类加载器JarLoader, 并实现了ClassLoaderSwapper进行类加载器的切换。

同样是破坏双亲委培机制,与SPI机制不同的是,它不通过双亲委派委托父类加载器加载,而是直接通过UrlClassLoader (JarLoader只是将路径下的所有jar加入classpath)去加载指定的插件类。概括其逻辑为: 加载类=》通过配置文件获取插件类名和路径=》实例化该插件UrlClassLoader=>将线程上下文加载器切换为UrlClassLoader并保存原来的线程上下文加载器=》加载插件实现类=》完成基于实现类的操作=》恢复原来的线程上下文加载器。下面是DATAX加载插件实现的部分源码

 

private Reader.Job initJobReader(JobPluginCollector jobPluginCollector) { 
        ClassLoaderSwapper classLoaderSwapper = ClassLoaderSwapper
            .newCurrentThreadClassLoaderSwapper(); 
    
        classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader(
                PluginType.READER, this.readerPluginName));

        Reader.Job jobReader = (Reader.Job) LoadUtil.loadJobPlugin(
                PluginType.READER, this.readerPluginName);

        classLoaderSwapper.restoreCurrentThreadClassLoader();
        return jobReader;
}

/*
* 为避免jar冲突,比如hbase可能有多个版本的读写依赖jar包,JobContainer和TaskGroupContainer
 * 就需要脱离当前classLoader去加载这些jar包,执行完成后,又退回到原来classLoader上继续执行接下来的代码
 */
public final class ClassLoaderSwapper {
    private ClassLoader storeClassLoader = null;

    private ClassLoaderSwapper() {
    }

    public static ClassLoaderSwapper newCurrentThreadClassLoaderSwapper() {
        return new ClassLoaderSwapper();
    }

    /**
     * 保存当前classLoader,并将当前线程的classLoader设置为所给classLoader
     */
    public ClassLoader setCurrentThreadClassLoader(ClassLoader classLoader) {
        this.storeClassLoader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(classLoader);
        return this.storeClassLoader;
    }

    /**
     * 将当前线程的类加载器设置为保存的类加载
     */
    public ClassLoader restoreCurrentThreadClassLoader() {
        ClassLoader classLoader = Thread.currentThread()
                .getContextClassLoader();
        Thread.currentThread().setContextClassLoader(this.storeClassLoader);
        return classLoader;
    }
}

 

本文的目的是梳理和理解目前主流的两种破坏双亲委派的方式,更好的理解双亲委派机制以及破坏双亲委派的目的和方式,同时对自己实现一些基于策略模式和插件化的项目有很好的参考意义

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于SPI机制和DataX插件热加载破坏双亲委派的思考 的相关文章

  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • Grails 3.x bootRun 失败

    我正在尝试在 grails 3 1 11 中运行一个项目 但出现错误 失败 构建失败并出现异常 什么地方出了错 任务 bootRun 执行失败 进程 命令 C Program Files Java jdk1 8 0 111 bin java
  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 加密 JBoss 配置中的敏感信息

    JBoss 中的标准数据源配置要求数据库用户的用户名和密码位于 xxx ds xml 文件中 如果我将数据源定义为 c3p0 mbean 我会遇到同样的问题 是否有标准方法来加密用户和密码 保存密钥的好地方是什么 这当然也与 tomcat
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • listview中listitem点击实现沿曲线移动动画效果

    现在有这样一个需求 点击listview中的任意一个item 出现一个轨迹为曲线的动画 我们知道Android动画分为帧动画 Frame 和补间动画 Tween 两种 帧动画和gif类似 将不同的帧以一定速度连续播放产生动画 需要我们事先准
  • 车牌识别中的不分割字符的端到端(End-to-End)识别

    传统的车牌识别过程是往往是这样的 车牌定位 gt 车牌判断 gt 车牌字符的分割 gt 车牌字符的识别 这种方法有个好处就是 仅仅需要较少的字符样本即可用于分类器的训练 在光照 相机条件好的情况下也能取得较好的效果 现在大多数商业车牌识别软
  • OKEX行情接口对接实例

    系统说明 开发语言 net core mssql2019 采用socket 订阅官方接收行情数据 可接收 市场 深度 行情 交易等数据
  • 炫酷的倒计时效果,祝福春节

    前言 春节将至 小福利 炫酷的倒计时效果 效果图 实现源码
  • JVM系列(七) JVM 垃圾收集器

    我们知道JVM会回收垃圾 但是每种垃圾收集器的收集机制和收集的方法都不一样 今天我们讨论下几种垃圾回收机制 1 按照垃圾区域划分垃圾收集器 我们可以按照垃圾存在的区域来划分垃圾收集器 垃圾在堆内的区域分为 新生代垃圾 老年代垃圾 新生代老年
  • aligned_alloc

    aligned alloc 函数 C C 函数签名 void aligned alloc size t alignment size t size 函数定义在
  • java代码实现下拉列表框多选操作

    实现操作 实现如图所示功能 前端没有学习 故本文只写后端内容 一 数据库 CREATE TABLE axa risk quantification id bigint 20 NOT NULL AUTO INCREMENT assets va
  • VSCode Remote-SSH (Windows)

    1 VSCode 安装 VSCode 2 安装扩展 Remote SSH Getting started Follow the step by step tutorial or if you have a simple SSH host s
  • Canny边缘检测算法原理及其VC实现详解(一)

    目录 1 边缘检测原理及步骤 2 Canny边缘检测算法原理 2 1 对原始图像进行灰度化 2 2 对图像进行高斯滤波 2 3 用一阶偏导的有限差分来计算梯度的幅值和方向 2 4 对梯度幅值进行非极大值抑制 2 5 用双阈值算法检测和连接边
  • jsp下拉框级联查询以及java代码实现

    需求描述 我们在开发过程中 很多页面查询 新增修改页面的下拉 需要通过一个下拉框的值 确定另一个下拉的值 典型的就是 选择年级 另一个下拉需要展示对应的班级 选择了班级 需要展示对应的学生 下面是存放地方 建筑物 级联查询建筑物与房间的例子
  • 《二叉搜索树OJ》

    文章目录 1 根据二叉树创建字符串 https leetcode cn problems construct string from binary tree 2 二叉树的层序遍历 https leetcode cn problems bin
  • v4l2框架API详解

    v4l2是linux内核中视频设备驱动框架 主要为了上层访问视频提供统一得标准接口 用户空间系统调用 open write read 内核空间 video device gt v4l2 device gt v4l2 subdev gt se
  • 【Windows系统】磁盘、Partition和Volume的联系与区别

    1 磁盘 Disk 磁盘 以下摘自微软 磁盘设备和分区 Win32 apps Microsoft Learn 硬盘由一组堆积的盘片组成 其中每个盘片的数据都以电磁方式存储在同心圆或 轨道中 每个盘片都有两个头 一个在盘片的两侧 在磁盘旋转时
  • ubuntu16安装新软件之后无法看到运行中的新软件

    安装新软件后 在启动器上点击新软件图标后 有小圆圈转动 看不到新软件界面 解决方法 系统设置 硬件显示 勾选 镜像显示 M 提醒 可能会限制分辨率选项 点击 应用 按钮 但字体模糊 解决方案 ctrl alt t打开命令行模式 xrandr
  • php yii2模块,Yii2模块自定义模块目录

    请教一下各位 yii2的模块创建后 比如如下的forum模块 官方的标准是如下目录结构 请问可以在该模块下手动创建一个目录么 比如common目录 如果可以的话调用该目录里的类文件与Yii1 1中的components一样么 现在想把该模块
  • Integer和int及String的总结

    Integer和int及String的总结 秉承着总结发表是最好的记忆 我把之前遇到的问题在这里总结和大家分享一下 希望大家共同进步 一 Integer和int 首先说下自动拆装箱 基本数据类型转换为包装类型的过程叫装箱 反之则是拆箱 其中
  • matlab 利用while循环计算平均值和方差

    一 该程序是用来测输入数据的平均值和方差的 公式 二 项目流程 1 State the problem假定所有测量数为正数或者0 计算这一系列测量数的平均值和方差 假定我们预先不知道有多少测量数据被录入 一个负数标志着测量数据输入结束 2
  • 网络层重点协议-IP协议(结构分析)

    IP协议数据报格式 一 4位版本号 用来表示IP协议的版本 现有的IP协议只有两个版本IPv4和IPv6 二 4位首部长度 IP协议数据报报头的长度 三 8位服务类型 3位优先权字段 已经弃用 4位TOS字段 和1位保留 字段 必须置为0
  • 实验4

    一 实验目的 1 掌握DPCM编解码系统的基本原理 2 初步掌握实验用C C Python等语言编程实现DPCM 编码器 并分析其压缩效率 二 实验内容 1 DPCM编解码原理 DPCM是差分预测编码调制的缩写 是比较典型的预测编码系统 在
  • 基于SPI机制和DataX插件热加载破坏双亲委派的思考

    在开始阅读之前请先思考以下两个问题 并希望您能再接下来的文章中找到答案 1 如果我自己实现了一个新的java lang String类 并通过UrlClassLoader加载使用该类 能否覆盖JDK中的 java lang String 2