Classloader、插件化开发(结合Presto)

如题所述

第1个回答  2022-06-27
注意:

双亲委派模式是在Java 1.2后引入的,其工作原理的是:

双亲委派模式优势

一般来说,例如程序 hello.jar 执行到:

会按照双亲委派模型进行加载类 Demo 。如果 Demo 在 hello.jar 内, AppClassLoader 就将其加载完成;但是如果例如 SPI 这种,既不在应用 hello.jar 内又不在系统类路径内,那么就要抛弃双亲委派模型,获取 线程上下文类加载器 加载( 线程上下文类加载器 默认是 AppClassLoader ,此时的 线程上下文类加载器 肯定是自定义的类加载器)。

自定义一个 破坏双亲委派模型的类加载器 的方法:

深入理解Java类加载器

这里介绍2种加载方式:

例如要加载类:

将其编译为class文件,存放在路径 /Users/root/Projects/idea/my/com 。

这时要加载它:

对于SPI这种,就需要用到ServiceLoader加载。可以参考地址: https://github.com/byamao1/try-plugin

需要注意:

知识点

插件化的一个重要目标就是利用类加载器实现类隔离(比如不同厂商版本的依赖包),其原理在于在类中(例如 Demo )隐式类加载器就是 Demo 的类加载器(一般为插件类加载器),对于插件中出现的插件外的类(例如SPI接口类)则不加载。

这里分析Presto的connector插件架构。

Presto的自定义类加载器 PluginClassLoader 继承 URLClassLoader 类并重写了 loadClass ,其类加载逻辑为:

注意:

Java 自定义 ClassLoader 实现隔离运行不同版本jar包的方式

从上面我们得知,如果采取ServiceLoader的SPI方案,应该在 resources/META-INF/services 中存放实现类的全限定名。有意思的是Presto的插件基本都没有这个声明文件,但是编译打包后插件模块的 target/classes 中却能找到。如果观察插件的 pom.xml 文件,就会发现 <packaging>presto-plugin</packaging> 。其实在根 pom.xml 中使用了presto自己的打包插件 presto-maven-plugin ,将该maven插件打开看就能发现 ServiceDescriptorGenerator 中会在打包时自动生成了声明文件。

SOFA-Ark 是蚂蚁金服开源的一款基于Java实现的轻量级类隔离加载容器。
具体可以参考博客: sofa-ark类隔离技术分析调研

站在插件的角度看待,我觉得:

你应该知道的Java Classloader - 知乎
相似回答