“WCF支持三种实例激活的类型:单调服务(Per-Call Service)会为每次的客户端请求分配(销毁)一个新的服务实例。会话服务(Sessionful Service)则为每次客户端连接分配一个服务实例。最后一种是单例服务(Singleton Service),所有的客户端会为所有的连接和激活对象共享一个相同的服务实例。”
对于Per-Call Service的翻译,我踌躇良久,最后还是决定按照Singleton服务的翻译,将其译为单调服务,意即为每次调用创建一个服务实例,与单例服务相对应。不知是否妥当?其实最好的翻译就是保持原文不变,但对于整本书而言,如果保持英文术语,也有许多不便的地方。
实例模式的配置通过ServiceBehavior完成,以下是ServiceBehaviorAttribute的定义:
public enum InstanceContextMode { PerCall, PerSession, Single } [AttributeUsage(AttributeTargets.Class)] public sealed class ServiceBehaviorAttribute : Attribute,... { public InstanceContextMode InstanceContextMode {get;set;} //More members }
单调服务(Per-Call Service)
单调服务如图所示:
执行步骤如下:
1. 客户端调用代理,代理将调用转发给服务。
2. WCF创建一个服务实例,然后调用服务实例的方法。
3. 当方法调用返回时,如果对象实现了IDisposable接口,WCF将调用IDisposable.Dispose()方法。
4. 客户端调用代理,代理将调用转发给服务。
5. WCF创建一个对象,然后调用对象的方法。
单调服务的一个最重要优势在于它能够节省资源,支持系统的可伸缩性。由于服务实例的生命周期只存在于一次调用期间,特别对于那些持有昂贵资源的服务实例而言,这种方式可以有效地提高系统性能。而且,销毁服务实例时,WCF不会断开与客户端(通过客户端的代理)的连接,这比创建实例与连接所消耗的资源要少得多。
单调服务体现的优势在事务编程与队列服务中更为明显,它可以保证在事务编程中实例状态的同步;而对于队列断开调用而言,则单调服务能够建立服务实例与离散队列消息之间的简单映射。
单调服务的配置通过ServiceBehavior,如下所示:
[ServiceContract] interface IMyContract {...} [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] class MyService : IMyContract {...}
注意,ServiceBehavior特性只能应用到类上面,这在前面介绍的特性定义可以看出。实际上,这也是合理的约束,因为如果将ServiceBehavior应用到接口上,由于接口是不能实例化的,自然会出现错误。
单调服务实例是状态相关的,但是由于实例会在调用之初创建,而在调用之后被销毁,因而这样的单调服务实例是无法保存状态的。为了解决这一问题,我们可以引入数据库或者文件保存状态,或者利用全局变量临时存储状态。那么为了获取状态,潜在的含义是单调服务的每个操作应该定义一个参数,用来传递状态或状态的ID。
书中有一句话非常重要:“如果单调服务真的与状态无关,就根本不需要单调激活模式。准确地讲,正是因为状态,特别是代价昂贵的状态,才需要使用单调模式。”很多时候,我们认为单调服务实例的生命周期存在于每次调用,因而想当然的认为这样的服务实例应该是无状态的。这样的操作可能只是简单执行某项任务,而不会对服务对象的属性进行操作。表面看起来确实如此,但在这里我们却忽略了我们采用单调服务的根本原因,是在于单调激活模式的本质就在于能够适时释放实例所持有的昂贵资源,这里的资源大体上讲就是一种状态。如果不需要维护状态,则以为着性能上没有太大的损耗,我们就没有必要采用单调激活模式了,毕竟频繁地创建与销毁实例,仍然会对性能造成一定的影响。
对于WCF服务而言,单调服务可以算是非常好的的实例激活模式。书中介绍:“一个有力的论据是单调服务更利于系统的可伸缩性。为了更好的支持可伸缩性,服务设计有一个黄金法则是10X,即设计出的每个服务应该能够处理至少多于需求一个量级以上的负载。这是一个工程学准则,工程师在设计系统时,绝不能够“鼠目寸光”,只考虑当前指定负载的处理。如果一幢大楼,只能够支撑当前需求确定的承重,还会有人胆敢居住吗?如果一座电梯,只能够承受规定的六位乘客的重量,还会有人愿意乘坐吗?软件系统同样如此。为什么不能针对当前指定的负载进行系统设计?假设采用这样的设计方式,一旦系统的每位用户增加了业务量,那么系统就会变得岌岌可危。设计良好的系统必须能够经久不衰,经得起时间的考验。为了实现这一目的,就需要应用10X的黄金法则,有效地利用单调服务所能提供的可伸缩性。采用单调服务的另一个有力论据是关于事务的处理。正如第7章介绍的那样,事务绝对是每个系统所必需的,单调服务有利于实现事务编程模型,而不用考虑系统的负载。”