经典技术文章翻译(1):COM+集成:.NET Enterprise Services 如何帮你建立分布式应用(2)

简介:
实现客户端
       当一个基于 CLR  组件服务类被编译和部署,你就需要在客户端调用它。长远来看,组件服务类没什么特别之处 ; 事实是使用 COM+  运行时服务是不相关的。  这个代码展示了简单类早期的定义 MyTxCfgClass:
using ESExample;
 
public class Client
{
 public static void Main(string[] args)
 {
    MyTxCfgClass tcc = new MyTxCfgClass();
     ... // use object as desired
 }
}
       当然,与所有的 CLR 代码,客户端必须引用组件服务类程序集。
csc /r:ESExample.dll Client.cs
细微的复杂性
       这里你会看到,服务类通过  .NET CLR 实现 COM+ 是相当的容易。  System.EnterpriseServices  命名空间里的类提供了可以使用 COM+ 运行时服务的 API 。运行时服务本身没什么改变;他们工作的方式还是  COM+ 开发者熟知的。已经说了,  集成 COM+ CLR  没有涉及到如此细微的复杂性。  有几个问题是使得使用 CLR 语言写  COM+  代码比我刚才提到的复杂的多。  有些问题会产生,因为 CLR 毕竟不是  COM   因为它可以做 COM 做不到的事情。这些问题是不能解决的 你只要知道如何 CLR 的特性如静态方法和垃圾回收器  如何影响 COM+  编程。
      
再学习这些问题前,你必须知道 CLR  的类和  and COM+  上下文环境的关系。  首先,调用继承自 ServicedComponent 的类的实例都会被 COM+  上下文环境边界侦听。这些对象称为上下文环境边界。调用没继承自 ServicedComponent 的类的实例就不会被上下文环境边界侦听。  这些对象称为 context-agile CLR 对象默认就是 context-agile   当你继承自 ServicedComponent 它们会变成 context-bound  ( 这个与  .NET remoting  上下文环境没有关系,我下面会讲到。  9 说明的这个架构
 9  上下文环境对象

     
非常有趣的是 CLR  对象可以实现类似 COM  对象和 COM+  上下文环境交互这样的行为。通过  COM ,调用对象通常默认都会被侦听 所有的对象都是 context-bound COM  对象是 context-agile  只有当它聚集了 freethreaded marshaler (FTM) 且不是第一个在 COM+  上下文环境里  被创建的对象 ( 因为它不是可识别的对象 )   这样情况下,调用不会被侦听。  新方法确保调用真的需要的时候被预处理和迟处理的好处是减少了侦听负荷。  特别地,如果组件服务类的实例返回了一个非组件服务类的实例  ( 例如一个  ADO.NET DataSet  对象 ) ,这个调用不会被侦听。  并且 DataSet 对象不需要做任何事情,它就是照常工作。
       第二个你应该知道的事情是,  除了减少真正需要的交叉上下文侦听外,  CLR/COM+ 集成尽可能地避免了托管类型和自有类型间的转换。  来自托管的 CLR  代码到 COM 的调用是比较昂贵的。重要的部分就是类型的前后转换 大部分在 CLR strings COM BSTRs 之间。  请求穿过 COM+ 环境边界需要  调用一些固有的代码,  组件已经相当聪明可以避免同样来自 CLR 且处在同一进程里的调用者和被调用者之间的类型转换。  或许有一天所有的 COM+  运行时服务都会用 CLR 语言重新实现,调转就不成问题了。  那时不管如何,这个优化都会使得 COM+  侦听更加快速。
静态方法和属性
       现在你知道了 CLR 代码如何关联上下文环境,  思考这个问题:如果一个基于 CLR  组件服务类  包括静态方法和属性访问器,  它将在什么上下文里执行呢?答案是调用者。  这个看起来不是很直观,  但是它确实很有意义当你想静态成员不是对象定义且不许要在对象驻留的上下文里访问。例如,组件服务类在  10 有个静态方法, 2   和静态属性, 4 。这个代码会在调用者的上下文里执行。  调用实例的方法 1   或者属性 3 ,通常在对象的上下文里执行。
     
这时你或许想知道当你在属性里保存了一个对象的静态引用且你想在另外一个上下问里引用会发生什么事情。基于 COM COM+ 编程里,  在被成为静态属性的全局变量里保存了一个原始的对象引用,  会导致严重的错误因为你不可以把对象不加包装地从原来的上下文里带走。使用基于 CLR COM+  代码,  这个就不是一个问题。  CLR  使用相当瘦的代理包装了每个组件服务类的实例子这样其它上下问的对象就不需要保留对象的直接引用。如果代码在一个保留基于 CLR  组件服务类引用在静态属性的的上下文执行。它实际保留的是一个引用。如果另一个上下文里的代码要通过静态属性访问它,  特定的代理就发现变化而且封装它自己保留的引用这样侦听就触发了。这个是有个优美的解决方案,本质上你可以任何地方保存基于 CLR 服务类的实例并且都会正确触发。
     
管理珍贵的资源
      我现在开始另外一个管理对象引用的话题 ' ,另外一个问题你必须注意 CLR 靠垃圾收集器回收内存。  这是个重要的事情因为它要自动帮助避免内存泄露并且释放闲置的内存。非常不幸的是,  垃圾收集器使得内存管理变的容易,但是他同样带来了其他问题,比如管理 COM+ 设计的对象变的困难。因此高效地管理资源是建立可伸缩的系统的关键,这正是 COM+  的设计目标,你需要知道如果合理地释放基于 CLR 的资源。
     
考虑  CLR 类使用到了 SqlConnection  对象连接数据库,  如下所示 :
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection =
      new System.Data.SqlClient.SqlConnection(…);
    …// use connection to execute statements
}
UseADatabase 方法的结束部分,  SqlConnection  对象被释放。  SqlConnection 对象封装了处理数据库的连接并且为了效率考虑被 ADO.NET 底层机制池化 (Beta 1  使用 COM+  对象池 ; Beta 2   使用了类似 COM+  对象池的机制 )   问题是  SqlConnection 对象管理的连接何时归还到对象池 不等垃圾收集器进入,就意识到 SqlConnection  对象不在被使用,就调用终结器。 finalizer  把连接归还给对象池,  然后 SqlConnection 对象的内存就被回收。
      
问题是数据库连接资源是非常珍贵的资源,你不能让他们无约束地飘荡在内存里,直到垃圾收集器来回收。  需要一些方法来回收这样的资源。一种方式就是强制垃圾收集器执行回收工作,如下所示 :
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection conn =
      new System.Data.SqlClient 。SqlConnection(…);
 … // use connection to execute statements
 conn = null;
 System.GC.Collect();   
}
然而,这个方法相当的笨拙且有很多潜在问题。
      更好的方法是调用 SqlConnection  对象实现的接口的  IDisposable.Dispose 方法。  IDisposable  接口在 System 命名空间,它规范拥有昂贵的要清理的资源的对象通过客户端定义操作释放资源代理垃圾收集器回收的行为。 SqlConnection 实现了 Dispose ,快速归还对象给对象池  ( 事实上和调用 finalizer 的作用一样 )
      
下面代码是新版本的 UseADatabase 方法,它显示的清除了 SqlConnection
public void UseADatabase(void)
{
 System.Data.SqlClient.SqlConnection conn =
      new System.Data.SqlClient.SqlConnection(…);
 try
 {
    … // use connection to execute statements
 }
 finally
 {
    Conn.Dispose();
 }
}
注意到 Dispose 出现在 finally 块里确保它可以执行,不管是否抛出异常。
      
那这个和 COM+ 与服务类有什么关系呢 首先,你的服务类很可能使用数据库连接和其它昂贵的资源,  所以如果你希望系统净化,你就应该知道如果合理地释放资源。  第二是,  所有基于 CLR  服务类  实现了 IDisposable.Dispose 方法,  因为基类, ServicedComponent 。你应该知道当客户端调用 Dispose 时发生了什么。默认实现的行为取决于你的组件服务类  使用了什么运行时服务。如果你没使用对象池激活,  Dispose 就会立即调用  finalizer ( 如果已经被垃圾收集器回收,就不会再调用 ) 。如果你的组件服务类  使用了对象池而不是 JIT  激活,  Dispose 调用 Deactivate 去通知对象已经离开它当前的上下文。然后它就调用  CanBePooled  去询问对象是否重用或销毁。  如果 CanBePooled 返回 true   对象会返回到对象池里。  返回 false   对象的 finalizer 就会调用  ( 如果已经被垃圾收集器回收,就不会再调用 )   非常重要是客户端为池化的对象调用方法 Dispose ,如下所示。
public void UseAPooledObject(void)
{
 MyPooledCfgClass pcc = new MyPooledCfgClass();
 try
 {
    …// use pooled object to do something
 }
 finally
 {
    Pcc.Dispose();
 }
}
       如果不调用 Dispose ,对象  ( 如描述的数据库连接 )   只有等到垃圾收集器回收资源。  最后,  如果你自己实现组件服务类的 Dispose 方法,  你必须调用基类的实现去实现这些描述的行为。
[ Synchronization(SynchronizedOption.Required) ]
public class MyCfgClass : ServicedComponent
{
 public new void Dispose()
 {
    … // do whatever
    Base.Dispose(); // call base to clean up
 }
}
     你或许想知道  JIT  激活和反激活一个对象在方法的结束。  那解决了资源的管理问题了吗 ? 答案是否。  反激活使得对象在结束调用前释放自己成员所有的资源,  同样包括想使用相同资源的的每个方法调用。你可以通过不保存任何资源的方式达到这个目的。如果你没有选择  JIT  激活  和反激活在每次方法调用的结尾,  知道客户端调用 Dispose 实际上是强制你的对象重激活到饭激活并且重新终结一次。通常情况下,  CLR 的转换不会改变的 JIT  激活规则。  应该避免使用它除非运行时服务需要它  ( 比如声明的服务 因为它不会更高效,    比你自己管理昂贵的资源效率低。
展望
      ServicedComponent  类继承自  System ContextBoundObject   它又继承自 System MarshalByRefObject   这个基类可以使对象可以通过 .NET remoting 机制  被访问到。在 Remoting 顶层  上进行 CLR/COM+ 集成有两个好处。首先你能通过 Remoting 层使用 SOAP 访问 COM+  运行时服务的远程对象。但是你不能够使用 SOAP 传递事务到另外的进程  ( 非你所愿,  但道理如此 )   第二点,打开了新版的新的基于 CLR Remoting 上下文架构实现的 COM+  运行时服务的方式  这是现在的 COM+ 所没有用到的。  将来一定会够发生。  真要这样,服务就可以与 SOAP 或者其他的传输无逢集成,并且上下文就可以真的可以扩展了。那时,  已经正确跨出一大步的 CLR  就会使得 COM+ 编程变的更加容易。
 
相关文章 :
Windows XP: Make Your Components More Robust with COM+ 1.5 Innovations
House of COM: Migrating Native Code to the.NET CLR
the "samples"technologies"component 服务  subdirectory of the.NET Framework SDK
事务 al COM+: Building  可伸缩的应用系统  by Tim Ewald (Addison-Wesley, 2001)
作者 Tim Ewald : DevelopMento 的首席科学家,   最近出版的   事务性 COM+:  创建可伸缩的应用系统  (Addison-Wesley  2001) 的作者
翻译 Frank Xu Lei : 程序员,技术博客 http://www.cnblogs.com/frank_xl/
来自 10  2001  MSDN 杂志



 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/321005,如需转载请自行联系原作者


相关文章
|
3月前
|
XML 开发框架 .NET
ASP.NET COR3.1 集成日志插件NLog
ASP.NET COR3.1 集成日志插件NLog
33 0
|
3月前
|
存储 网络协议 中间件
信管知识梳理(二)常规信息系统集成技术
国际标准化组织(ISO)提出的网络体系结构模型,也叫做开发系统互连参考模型(OSI/RM),通常叫做OSI参考模型
480 1
信管知识梳理(二)常规信息系统集成技术
|
4月前
|
XML SQL 开发框架
|
19天前
|
SQL 数据库 Windows
SpringCloud集成seata分布式事务控制
SpringCloud集成seata分布式事务控制
14 0
|
2月前
|
消息中间件 存储 物联网
EMQ
|
2月前
|
存储 NoSQL API
EMQX Enterprise 5.4 发布:OpenTelemetry 分布式追踪、OCPP 网关、Confluent 集成支持
新版本提供 OpenTelemetry 分布式追踪与日志集成功能,新增了开放充电协议 OCPP 协议接入能力,并为数据集成添加了 Confluent 支持。此外,新版本还进行了多项改进以及 BUG 修复,进一步提升了整体性能和稳定性。
EMQ
1115 2
EMQX Enterprise 5.4 发布:OpenTelemetry 分布式追踪、OCPP 网关、Confluent 集成支持
|
6月前
|
存储 Java Nacos
如何在Spring Cloud项目中集成Seata,实现分布式事务的管理和控制?
如何在Spring Cloud项目中集成Seata,实现分布式事务的管理和控制?
122 0
如何在Spring Cloud项目中集成Seata,实现分布式事务的管理和控制?
|
3月前
|
IDE 前端开发 JavaScript
【C#】C# 开发环境配置(Rider 一个.NET 跨平台集成开发环境)
【1月更文挑战第26天】【C#】C# 开发环境配置(Rider 一个.NET 跨平台集成开发环境)
|
3月前
|
开发框架 网络安全 数据库
典型应用集成技术
【1月更文挑战第11天】典型应用集成技术。
21 0
|
3月前
|
NoSQL 前端开发 Java
Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)
Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)
Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)

热门文章

最新文章