JointCode.Shuttle 是一个用于进程内 AppDomain 间通信的服务架构(不支持跨进程),它旨在取代运行时库提供的 MarshalByrefObject 的功能。
1. 使用场景
在 .net / mono 开发中,一般不太需要创建新的 AppDomain,但在一些 下,也许我们需要使用一个新的 AppDomain,并在其中执行一些操作。
当代码跨越 AppDomain 边界访问另一个 AppDomain 时,便产生了跨 AppDomain 通信。这时候,您可以考虑使用 JointCode.Shuttle。
2. 传统跨 AppDomain 通信方式的问题
一般来说,在进行跨 AppDomain 调用时,大部分人使用运行时库默认提供的、基于 MarshalByrefObject 类继承的通信机制。这种方式最简单,只要让需要跨 AppDomain 操作的类继承 MarshalByrefObject 即可,实现起来很方便。例如:
1 namespace JoitCode.Shuttle.SimpleSample 2 { 3 public class MyService : MarshalByRefObject 4 { 5 public void Do() { } 6 } 7 8 class Program 9 {10 static void Main(string[] args)11 {12 // 在默认 AppDomain 中创建一个子 AppDomain13 var serviceDomain = AppDomain.CreateDomain("ServiceDomain", null, null);14 15 var myService = (MyService)serviceDomain.CreateInstanceAndUnwrap16 (typeof(MyService).Assembly.FullName, 17 "JoitCode.Shuttle.SimpleSample.MyService");18 19 myService.Do();20 21 Console.Read();22 }23 }24 }
简单是简单,但这种方式也有一些局限性。有什么局限性呢?
- AppDomain 的访问是单点的,即它只能由创建它的宿主(或称父 AppDomain)访问,而不能由其他 AppDomain 访问,即使是由相同宿主创建的其他 AppDomain,甚至其宿主的父宿主也不行。
- 缺少灵活性,由于要求服务类必须继承 MarshalByrefObject 类,这限制了灵活性。
- 性能问题,测试结果表明使用这种方式的跨 AppDomain 通信要比普通对象访问慢几百到一千倍()
- 双向通信,使用这种方式无法实现双向通信。
除了 MarshalByrefObject 之外,可能还有 remoting、wcf 甚至于消息队列等等跨进程的方式也可以实现跨 AppDomain 通信(作者自己没尝试过)。这些方式或多或少消除了上述那些限制,然而我们也能想象得到,本来是进程内通信的事情,现在弄成进程间通信,凭空增加许多开销,那么它们的性能一定比 MarshalByrefObject 更低,而且学习成本也会更高,实现起来也更复杂。
3. JointCode.Shuttle 的特点
与 MarshalByrefObject 相比,JointCode.Shuttle 除了具备相同的跨 AppDomain 通信的功能之外,还有自己的一些特点:
- 面向接口/服务
- 使用 Attribute 方式来标注服务 / 定义服务元数据,对代码无侵入
- 强类型,使用方便(MarshalByrefObject 方式依赖 magic string 来查找服务类)
- 内置 IoC 功能,自动管理服务的依赖项
- 支持延迟加载类型 / 程序集
- 简单,快速上手
- 支持 .net 2.0
JointCode.Shuttle 是一个非常新颖的框架,功能还不是很完备。尽管作者将会在未来继续完善现有功能,并推出更多新的功能,但目前还是存在一些不足,主要包括:
- 仅支持 32 位应用程序(x86 目标平台)
- 仅支持 Windows(目前仅支持 .net framework,不支持 mono)
- 暂不支持跨 AppDomain 事件
- 测试得不够
5. 如何使用 JointCode.Shuttle
如果您对 JointCode.Shuttle 有兴趣,请移步前往 ,我们提供了一个简单的示例来说明如何使用这个框架。