插件平台的类加载机制

简介:

作为一个插件平台,除了要解决在运行时插件的交互问题外,还需要解决一个非常重要的问题——类加载。原因在于:(1)类加载机制可以绕过默认类型加载器按需自动加载每一个插件的所有类型;(2)插件具备独立性,即一个插件的运行不能对其它插件和插件内核平台产生影响,这使得类加载机制必须维护每一个插件的类型;(3)每一个插件可能会引用同一个Class的不同版本,这要求类加载机制必须能够加载多个版本的同一个类并为每一个插件维护其特定版本的类型。本文将讨论一下基于Java和.NET的插件平台的类加载机制。

 

在Java平台,每一个类型是由ClassLoader和类型全称唯一标识。ClassLoader具有父子关系的层次结构。来自于不同ClassLoader的相同全名的类被视为不同类型。ClassLoader提供了简单、灵活且优雅的类型加载机制,在默认的ClassLoader中,利用其进行类型加载时,它会先尝试使用父ClassLoader进行加载,如果在父ClassLoader没有加载成功,才考虑用子ClassLoader中加载。如果请求子ClassLoader加载的类型,若在父ClassLoader中加载成功,则子ClassLoader不会再加载,会直接从父ClassLoader中获取。这意味着,一个在父ClassLoader中加载的类型可以和所有的子ClassLoader共享,不过,子ClassLoader间是不能够共享类型的(这种父ClassLoader向子ClassLoader的共享行为可以通过自定义ClassLoader来改变)。考虑到Java的默认ClassLoader机制,在我看来理想状态下的插件平台的类加载机制的设计应该如下图(虽然我不是专业的Java开发人员,但是对其ClassLoader非常感兴趣,于是好好研究了一下,个人觉得该图的ClassLoader层次设计要比JavaPluginFramework优雅)。这个类加载机制由3层ClassLoader组成,类加载管理器必须严格控制线程执行过程中的ClassLoader,从而实现插件独立行、多版本类型支持、插件与平台无关性。(附:Flex的类型加载类似于Java的ClassLoader,只不过它被命名为AppDomain,估计是吸收了.NET和Java的优点。不过,在开发插件化的Flex平台时,如果采用的是分层的AppDomain的话,很容易碰到TypeA转换成TypeA异常的问题,我把它称为Singleton Hell Issue,因为Flex底层类库使用了不少的单件类,如果一个AppDomain注册一个实例,另一个AppDomain获取并使用则出现异常,这类异常在Flex SDK 3.0中大量存在。因此,我们在使用Java的ClassLoader和Flex的AppDomain的时候,需要谨慎并精细。)

 

 

(鉴于本文有点抽象,于是举个例子说明一下 )假设在当前线程运行到Plugin B的代码,插件管理器在执行Plugin B的代码之前已经将其类加载器设置为PluginClassLoader了,因此,线程在执行代码的过程中,如果碰到新的类型,则将从PluginClassLoader B中加载所需的类型;同理,当执行Plugin A的代码时,其加载器使用的是PluginClassLoader A。这为插件类型空间提供了独立性,从而使得在A和B插件可以使用同一个类型的不同版本。 

 

在.NET平台中,每一个类型是由AppDomain + 程序集全名 + 类全名来唯一标识的。微软在程序集中直接声明了版本号。因此,CLR Loader允许在一个AppDomain存在多个版本的相同程序集,这意味着在同一AppDomain可能存在不同版本的类型。.NET的程序集相对于Java的Package而言,它天生就对版本进行了标识,也就直接解决了插件平台类型加载的多版本问题。不过,遗憾的是,加载到一个AppDomain的程序集是无法被卸载的,除非卸载整个AppDomain。为了实现插件的动态卸载,这就要求为每一个插件创建一个独立的AppDomain,但这又引入了Remoting Call,极大降低了性能。我在这里提到的类加载机制,为了性能和系统简单性考虑,忽略了插件的动态卸载,仅为一个插件平台使用一个AppDomain,并引入了一套新的类型加载机制,该类型加载机制能够按需加载程序集,其设计,部分借鉴了Java ClassLoader的思路,如下图。在此机制的TypeLoader由其加载的Assembly组成,也具备有一个层次结构,每一个插件的类型加载都使用自身的BundleTypeLoader进行加载。BundleTypeLoader会从CoreTypeLoader、SharedLibTypeLoader和依赖的BundleTypeLoader加载所需的类型。

 

 

本文基于.NET的TypeLoader将基于Assembly.LoadFile实现多版本程序集的加载,因此,我们需要为每一个插件管理好其相应的程序集,在Bundle B执行过程中,它将使用BundleTypeLoader B来加载所需的类型,而这个Loader会根据需要将对应的程序集加载到当前应用域。从而实现,在插件A和B,其类型加载仅限于从插件本身依赖的程序集加载,虽然所有的程序集都在同一个应用域,但已经被分层管理起来了。(其实原理就只有一句话“确保在插件平台上线程执行过程中能够加载到正确的类型”,比如执行插件A的代码时,插件A依赖的类型必须在其类加载器存在。)



本文转自道法自然博客园博客,原文链接:http://www.cnblogs.com/baihmpgy/archive/2009/11/12/1601753.html,如需转载请自行联系原作者

目录
相关文章
|
4月前
|
Arthas Java 测试技术
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
Java字节码文件、组成、详解、分析;常用工具,jclasslib插件、阿里arthas工具;如何定位线上问题;Java注解
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
|
6月前
|
Java 关系型数据库 MySQL
GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现
在 2024 OpenTelemetry Community Day 会议中,阿里云可观测工程师张乎兴(望陶)和饶子昊(铖朴)为大家带来了《GraalVM 静态编译下 OTel Java Agent 的自动增强方案与实现》的演讲分享,介绍阿里云在相关领域的探索方案,本文是相关分享对应的中文整理。
282 22
|
5月前
|
JSON Java Maven
Native扩展开发的一般流程(类似开发一个插件)
这篇文章介绍了Java服务开发的大致流程,包括编写Java服务类、打包成jar包、在配置文件中进行服务配置、在代码中调用服务以及如何检查服务调用是否成功,提供了详细的步骤和说明,帮助开发者理解服务从开发到部署的全过程。
Native扩展开发的一般流程(类似开发一个插件)
|
6月前
|
算法 Java 应用服务中间件
开发与运维机制问题之在Tomcat的类加载机制中,如果BootstrapClassLoader没有加载成功类,Tomca如何解决
开发与运维机制问题之在Tomcat的类加载机制中,如果BootstrapClassLoader没有加载成功类,Tomca如何解决
41 0
|
7月前
|
JSON 监控 Java
编写电脑监控软件的Groovy脚本:JVM生态系统的整合与扩展
使用Groovy编写脚本监控Java虚拟机(JVM)的健康状况,包括内存使用和CPU利用率。脚本可自动将数据提交至指定网站,确保及时发现系统问题,防止服务中断。通过结合Runtime和OperatingSystemMXBean类获取系统信息,利用Groovy的HTTP客户端库POST数据到监控网站,实现高效稳定的系统监控。
131 0
|
8月前
|
Java 编译器 Spring
[Spring 企业应用加速小技巧]将bean扫描提前到编译器,加快应用启动速度
[Spring 企业应用加速小技巧]将bean扫描提前到编译器,加快应用启动速度
100 0
|
前端开发 Java C语言
JVM核心类加载器及类加载的全过程
JVM核心类加载器及类加载的全过程
134 0
JVM核心类加载器及类加载的全过程
|
Java Android开发 p3c
阿里祭出大器,Java代码检查插件
前阵子阿里巴巴发布了<<阿里巴巴Java开发手册(终极版)>>。 不久,又一气呵成发布了Eclipse/Intellij Idea下的代码检测插件PC3,可谓是国内代码优秀的检测插件。此插件检测的标准是根据<<阿里巴巴Java开发手册(终极版)>>上面制定的规定进行检测的。
172 0
阿里祭出大器,Java代码检查插件
|
Web App开发 移动开发 JSON
前端工具类网址推荐
前端工具类网址推荐
112 0
|
Android开发
【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )(一)
【Android 插件化】Hook 插件化框架 ( 反射工具类 | 反射常用操作整理 )(一)
195 0

热门文章

最新文章