WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance
我们知道WCF有3种典型的对service instance进行实例化的方式,他们分别与WCF的三种InstanceContextMode相匹配,他们分别是PerCall,PerSession和Single。PerCall为每次service invocation创建一个新的service instance; 而PerSession则让一个service instance处理来自通过各Session(一般是同一个proxy对象)的调用请求;而Single则是用同一个service instance来处理所有的调用请求。SOA的一个原则是创建无状态的service(stateless service),PerCall应该是我们经常使用的实例化方式,尽管PerSession是默认的InstanceContextMode。
但是对于PerCall这种实例化方式来说,为每次service请求都创建新的service instance,有时候显得有点极端,频繁的对象创建会对系统的性能造成一定的影响。我们能够以池的机制(Pooling)进行对象的获取和创建呢:当service调用请求抵达service端,先试图从池中获取一个没有被使用的service instance,如何找到,直接获取该对象;否则创建新的对象。当service instance对象执行完毕,将对象释放到池中以供下次service 调用使用。
一、实现原理
我们今天就来试着实现这样的service instance提供机制。主要的实现原理是:让所有的service实现一个公共的inte易做图ce(IPooledObject),定义了IsBusy的属性表明该对象当前是否正在被使用;为每个service type维护一个weak reference列表,每个weak reference对应一个确定的service instance,我们姑且将该weak reference列表成为该service type对应的对象池(object pool);为了处理service的调用需要提供一个确定的service instance的时候,遍历对象池,通过weak reference的Target属性找出一个可用的service instance(IsBusy=false)。如何顺利找到这样的service instance,则将其从对象池取出,将IsBusy属性设为true;如何没有找到,则通过反射创建一个新的service instance,将IsBusy设为true,同时利用weak reference将其包装,并将该weak reference加入到对象池中,最后返回该service instance用于处理service 调用。当service 调用结束,不是直接将其dispose掉,而是将其释放回对象池,供后续的service调用使用。
由于我们通过weak reference来实现对象池,weak reference引用的service instance是可以被GC回收的,这样做的好处是充分利用的GC的垃圾回收功能,避免不需要的service instance常驻内容,带来不必要的内存压力。此外,正是因为weak reference引用的service instance是可以被GC回收,我们需要一个后台的任务定期地将已经被回收的weak reference清除掉。
和本系列前两篇文章(WCF和Unity Appliation Block集成;WCF和Policy Injection Application Block集成)一样,涉及的是service instance的提供的问题,所以,我们也是通过自定义InstanceProvider来实现以对象池的机制创建service instance的目的。
四、PooledInstnaceProvider的创建
在创建我们自定义的InstanceProvider之前,我们先来介绍几个辅助的class:
I、IPooledObject
1: namespace Artech.WCFExtensions
2: {
3: public inte易做图ce IPooledObject
4: {
5: bool IsBusy
6: { get; set; }
7: }
8: }由于我们要判断service instance是否可用,我们让所有的service type实现IPooledObject inte易做图ce。IPooledObject 仅仅定义一个bool类型的属性:IsBusy。通过该属性判断service instance是否正在被使用。
II、WeakReferenceCollection和WeakReferenceDictionary
1: namespace Artech.WCFExtensions
2: {
3: public class WeakReferenceCollection:List<WeakReference>
4: {}
5:
6: public class WeakReferenceDictionary : Dictionary<Type, WeakReferenceCollection>
7: {}
8: }WeakReferenceCollection仅仅是WeakReference的列表,WeakReferenceDictionary 则是key为Type,value为WeakReferenceCollection的dictionary。在提供service instance的时候,就是根据service type为key找到对应的WeakReferenceCollection。
III、PooledInstanceLocator
1: namespace Artech.WCFExtensions
2: {
3: public static class PooledInstanceLocator
4: {
5: internal static WeakReferenceDictionary ServiceInstancePool
6: { get; set; }
7:
8: static PooledInstanceLocator()
9: {
10: ServiceInstancePool = new WeakReferenceDictionary();
11: }
12:
13: public static IPooledObject GetInstanceFromPool(Type serviceType)
14: {
15: if(!serviceType.GetInte易做图ces().Contains(typeof(IPooledObject)))
16: {
17: throw new InvalidCastException("InstanceType must implement Artech.WCFExtensions.IPooledInstance");
18: }
19:
20: if (!ServiceInstancePool.ContainsKey(serviceType))
21: {
22: ServiceInstancePool[serviceType] = new WeakReferenceCollection();
23: }
24:
25: WeakReferenceCollection instanceReferenceList = ServiceInstancePool[serviceType] ;
26:
27: lock (serviceType)
28: {
29: IPooledObject serviceInstance =null;
30: foreach (WeakReference weakReference in instanceReferenceList)
31: {
32: serviceInstance = weakReference.Target as IPooledObject;
33: if (serviceInstance != null && !serviceInstance.IsBusy)
34: {
35: serviceInstance.IsBusy = true;
36:  
补充:综合编程 , 其他综合 ,