插件平台的类加载机制

简介:

作为一个插件平台,除了要解决在运行时插件的交互问题外,还需要解决一个非常重要的问题——类加载。原因在于:(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,如需转载请自行联系原作者

目录
相关文章
|
10天前
|
监控 前端开发 安全
JVM工作原理与实战(十四):JDK9及之后的类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JDK8及之前的类加载器、JDK9及之后的类加载器等内容。
19 2
|
8月前
|
运维 算法 安全
阿里P8写出的2023最新版《深入理解Java虚拟机3》轻松学会JVM底层
Java是目前用户最多、使用范围最广的软件开发技术,Java的技术体系主要由支撑Java程序运行的虚拟机、提供各开发领域接口支持的Java类库、Java编程语言及许许多多的第三E方Java框架(如Spring、 MyBatis等) 构成。在国内,有关Java类库API、Java语言语法及第三方框架的技术资料和书籍非常丰富,相比而言,有关Java虚拟机的资料却显得异常贫乏。
|
12月前
|
消息中间件 JavaScript 小程序
巴拿马项目:打通 JVM 与 Native 代码
巴拿马项目:打通 JVM 与 Native 代码
|
存储 缓存 前端开发
插件化揭秘(一.类是如何一步一步被加载到虚拟机中的)
前面一篇文章我们讲解了关于`Class文件类文件结构`,而Class文件最终需要加载到虚拟机内存中才能被使用, 本章就来讲解下,**Class文件被加载到虚拟机中的过程**
|
前端开发 Java Unix
【Java实战系列】如何扩展加载Jar包?|周末学习
【Java实战系列】如何扩展加载Jar包?|周末学习
164 0
|
监控 数据可视化 算法
Java虚拟机-常用工具
Java虚拟机-常用工具
119 0
Java虚拟机-常用工具
|
Web App开发 监控 数据可视化
【JVM实践入门篇】: VisualVM的插件下载
【JVM实践入门篇】: VisualVM的插件下载
449 0
【JVM实践入门篇】: VisualVM的插件下载
|
缓存 前端开发 Java
JVM深入学习(二十五)-字节码文件概述
通过字节码文件了解java编译的过程,进而深入学习jvm
212 0
|
Java Android开发 p3c
阿里祭出大器,Java代码检查插件
前阵子阿里巴巴发布了<<阿里巴巴Java开发手册(终极版)>>。 不久,又一气呵成发布了Eclipse/Intellij Idea下的代码检测插件PC3,可谓是国内代码优秀的检测插件。此插件检测的标准是根据<<阿里巴巴Java开发手册(终极版)>>上面制定的规定进行检测的。
130 0
阿里祭出大器,Java代码检查插件
|
架构师 Java 编译器
组件化框架设计之apt编译时期自动生成代码&动态类加载(二)
组件化,框架设计,编译,动态类加载,阿里