CLR类加载简述与OSGi.NET插件平台类加载机制简述

简介:
一个插件平台除了需要考虑插件的结构、插件位置、插件类型空间、插件依赖、插件通讯、插件多版本支持、插件国际化等插件所需的基本要素之外,还需要考虑一个开发人员如何开发、调试和部署插件。本文简要描述了插件类型空间相关的知识——CLR Loader、CLR Loader VS Java ClassLoader和插件的类型空间及类加载机制实现。

1 CLR Loader

关于CLR加载器的详细描述可以查看《Essential .NET, Volume 1: The Common Language Runtime》,也可以下载我翻译的关于CLR部分的文档“CLR加载器 /Files/baihmpgy/CRL加载器.rar”。在这里我将描述一下书中没有说明的关于加载器的一些信息,这些信息包括:(1)何时触发类加载;(2)LoadFile的妙用及缺陷;(3)AppDomain.AssemblyResolve和AssemblyLoad事件。

在我目前认知情况下,我知道类加载发生在:A)CLR执行线程进入一个方法之前会触发JIT对方法进行编译并加载这个方法所需要的类型;B)调用Type.GetType等系统方法也会触发类型加载。为了让读者更好了解到类加载时机,我编写了一个Sample。该Sample的目录结构如下:
ClassLoaderTesting.exe
ClassLibrary1.dll
ClassLibrary2.dll
lib<directory>
---CL3<directory>
--------ClassLibrary.dll
你可以点击此处 /Files/baihmpgy/ClassLoaderTesting.rar下载Sample源码,在Program.cs的Main方法你可以看到类加载实验,AssemblyLoad和AssemblyResolve事件发生的时机。

LoadFile和LoadFrome的区别在于LoadFile每次加载一个程序集的时候,不管目前AppDomain是否已经加载了该程序集,它都会加载一次。此外,LoadFile不会加载目标程序集引用的程序集。它为我们提供了加载多版本程序集支持且可以做到按需加载一个程序集依赖的所有程序集。当然,目前而言,我所知的LoadFile的一个最大缺点,就是每次加载一个程序集后,它会Lock住程序集文件。这个缺点在支持插件调试时非常突出。

AssemblyResolve事件在CLR类加载器无法加载到所需类型时触发,它赋予了我们自定义类型加载的扩展,相反AssemblyLoad事件则发生在程序集被加载时。你可以通过调试ClassLoaderTesting这个项目来检查类型何时加载以及这两个事件何事触发。

2 CLR Loader Vs Java ClassLoader

这个问题比较古老了,已经有人比较过CLR Loader和Java ClassLoader。不过,要想公平公正的进行比较还真不容易,这就像公正比较Java和C#,J2EE和.NET一样。前一段时间,就有很多人在批Java。在比较CLR Loader和Java ClassLoader之前,先说几句废话。我先声明一下,我是一个C#程序员,也接触过Java。对Java类加载机制、Flex类加载机制有一定的实践。我体会到一些.NET平台相对于Java平台所不具备的东西,而这些差距除了.NET只支持Windows和Linux之外,还有就是.NET缺少的开放规范和缺少灵活的类加载机制。众所周知,Java有一堆的规范,比如JDBC、JMS、JMX、JNDI、JTX等等,当然,也有基于这些规范的各种Providers,基于Java平台我们可以有很多挑选的余地,并且可以从这些高端的开放规范中学习到很多的知识,.NET平台就很少有开放规范了,如果你非得说C#语言规范的话,那也算,:)。那些标榜“C#比Java绝对好”结论相关的文章我一般都懒得回复,因为这没有任何意义,我只想根据实际需要选择更好的,而不是片面的排斥。要知道,现在用Java的程序员可是C#的几倍,而且Java已经被认为是云计算的标准开发语言(插一句,我不幸的是用C#构建了一个SaaS引擎,深受客户的质疑),存在即合理。

言归正传,我将在http://blog.joycode.com/junfeng/archive/2004/04/10/18901.joy这篇文章之上谈一下二者。在Java,类是通过ClassLoader和类型全程来标识的,这意味着一个ClassLoader不能加载重复的类型,但是两个ClassLoader可以加载同一个名称的类型。不过这时候,被加载的这两个类型创建的实例就是隶属于不同类型了。据我说知,Java类加载触发有两种情况:A)JVM执行过程中;B)Class.forName。JVM在执行字节码的过程中,碰到一个未知类型后,会从当前线程获取对应的ClassLoader,然后使用ClassLoader加载类型。ClassLoader加载类型采用一种层级方式,它首先先调用父类加载器进行加载,如果加载不到才使用当前线程的ClassLoader进行加载。我们可以通过重写ClassLoader对JVM类型加载进行扩展。著名的Eclipse的OSGi内核——Equniox就是通过重写ClassLoader自定义了一个插件类型空间的类型加载器。Class.forName则是显式调用当前线程类加载器加载类型的方法了。很多Java组件框架都是通过扩展ClassLoader来实现模块化技术的,比如JBoss和NetBeans。

CLR加载器概念,我们接触的机会很少,相反,我们对Assembly.Load/LoadFrom/LoadFile、Type.GetType倒是经常碰到了,你可以通过《Essential .NET, Volume 1: The Common Language Runtime》该书深入理解CLR加载器。和Java ClassLoader相比,它的缺点主要有:(1)扩展性差;(2)加载的类型卸载的唯一方式是随着AppDomain一起被卸载。扩展性差表现在,实现CLR自定义类型加载只能通过AppDomain.AssemblyResolve来实现(还有一种方法,就是可以通过.config文件来配置类型加载,但这种方法是静态的,我没有把它当成一种方法),Assembly.Load/LoadFrom/LoadFile这些方法并不能实现对CLR加载器进行扩展,它们只是一些补充,原因很简单,在执行“Class3 cls = new Class3();”时,Class3只能是由CLR来加载的。第二个缺点,很明显,一个类型一旦被加载了,它是无法卸载的,因为在C#,我们在不使用低性能和跨进程调用的AppDomain下是无法实现一个支持动态更新的插件平台。

我的结论:Java ClassLoader简单优雅、功能强大、非常灵活,但对多版本不提供支持;CLR Loader非常简单、支持多版本、但不太灵活且扩展性稍差。

3 OSGi.NET BundleLoader

OSGi.NET是OSGi规范移植到.NET的实现。OSGi是一个基于Java的动态模块化系统的规范。它提供了模块化与插件化、面向服务、安全与隔离和模块扩展支持的功能。由于OSGi具有规范的模块化与插件化定义,且已经经过了Eclipse IDE考验,我们便制定了基于C#的OSGi.NET开放服务规范并基于C#开发实现。

在设计OSGi.NET过程中,模块层花费了大量的设计和开发的时间。我从易用性、类型空间独立性、类加载性能等方面考了,设计了一个几乎和OSGi模块类加载器一样优雅的插件类型加载机制。它类似OSGi实现了一个插件的独立类型空间,在OSGi.NET中,一个插件能加载的类型由插件与子插件本地程序集、插件与子插件依赖程序集、插件动态依赖程序集组成,通俗的讲,一个插件只能从本地和依赖的程序集加载所需的类型。这种方式使得多版本程序集支持也变得可能。OSGi.NET插件类型加载由BundleLoader即插件类加载器来实现,其实现原理和OSGi类似。

不过,为了实现每一个插件独立的类型空间,我们需要对CLR加载器进行扩展,其方式如下:
复制代码
 1  AppDomain.CurrentDomain.AssemblyResolve  +=   new  ResolveEventHandler(DomainAssemblyResolve);
 2 
 3  Assembly DomainAssemblyResolve( object  sender, ResolveEventArgs args)
 4  {
 5       string  resolvingAsmName  =  args.Name;
 6      AssemblyName name  =   new  AssemblyName(resolvingAsmName);  // 获取程序集全名。
 7      Assembly asm  =  SearchAssemblyFromAllBundles(name);  // 从所有Bundle的程序集中查找匹配的程序集并加载。
 8 
 9       return  asm;
10  }
复制代码

 


到目前为止我对OSGi.NET的插件化支持还算满意,但限于个人对Java ClassLoader、CLR Loader和OSGi等精深知识理解还不够深入,如有错误,欢迎指正。



本文转自道法自然博客园博客,原文链接:http://www.cnblogs.com/baihmpgy/archive/2010/06/04/1751768.html,如需转载请自行联系原作者
目录
相关文章
|
XML 开发框架 .NET
ASP.NET COR3.1 集成日志插件NLog
ASP.NET COR3.1 集成日志插件NLog
150 0
|
8月前
|
存储 算法 安全
.NET 平台 SM2 国密算法 License 证书生成深度解析
授权证书文件的后缀通常取决于其编码格式和具体用途。本文档通过一个示例程序展示了如何在 .NET 平台上使用国密 SM2 算法生成和验证许可证(License)文件。该示例不仅详细演示了 SM2 国密算法的实际应用场景,还提供了关于如何高效处理大规模许可证文件生成任务的技术参考。通过对不同并发策略的性能测试,开发者可以更好地理解如何优化许可证生成流程,以满足高并发和大数据量的需求。 希望这段描述更清晰地传达了程序的功能和技术亮点。
900 14
.NET 平台 SM2 国密算法 License 证书生成深度解析
|
10月前
|
Linux API C#
基于 .NET 开发的多功能流媒体管理控制平台
基于 .NET 开发的多功能流媒体管理控制平台
161 9
|
11月前
|
机器学习/深度学习 人工智能 Cloud Native
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台。本文深入解析 .NET 的核心优势,探讨其在企业级应用、Web 开发及移动应用等领域的应用案例,并展望未来在人工智能、云原生等方面的发展趋势。
220 3
|
11月前
|
存储 设计模式 编解码
.NET 8.0 通用管理平台,支持模块化、WinForms 和 WPF
【11月更文挑战第5天】本文分析了.NET 8.0 通用管理平台在模块化、WinForms 和 WPF 方面的优势。模块化设计提升了系统的可维护性和可扩展性,提高了代码复用性;WinForms 提供了丰富的控件库和简单易用的开发模式,技术成熟稳定;WPF 支持强大的数据绑定和 MVVM 模式,具备丰富的图形和动画功能,以及灵活的布局系统。
482 2
|
12月前
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
177 0
|
12月前
|
前端开发 JavaScript C#
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
258 0
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
283 0
|
开发框架 监控 .NET
|
JSON 开发框架 API
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
【推荐100个unity插件之20】一个强大的JSON处理库——Newtonsoft.Json(也称为Json.NET)
1197 0
下一篇
oss教程