zoukankan      html  css  js  c++  java
  • 实例上下文模式:单例模式

           单例模式效果可以用下面这张图表示,服务端的服务实例只有一个,任何一个客户端访问的服务端都是相同的服务实例。意味着服务端可以留下不同客户端的脚印。

                                       

          使用也很简单,只需要将ServiceBehavior的上下文模式InstanceContextMode设置为Single即可。可以参照上一篇介绍实例上下文模式:单调模式

        [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
        public class Calculator : ICalculator,IDisposable
        {
           ......
        }
    

        

          上篇介绍实例上下文模式时有些概念没有讲清楚。这里来补一下。

          ServiceHost有两个有参数的构造函数,分别是

     public ServiceHost(object singletonInstance, params Uri[] baseAddresses);
     public ServiceHost(Type serviceType, params Uri[] baseAddresses);
    

       第一个构造函数,singletonInstance是指服务实例,即new Calculator()创建的实例对象。

       第二个构造函数是指服务实例的类型,即typeof(Calculator)获得。

       baseAddresses均指终结点的基地址,这里需要注意,每一种Binding类型只能有一个基地址。例如下面寄宿代码将会报错,因为baseAddrs中含有两个http的基地址。

      

      回到正题,通过观察ServiceHost的构造函数代码。会将服务实例放入singletoninstance,类型放入serviceType。  这两个字段在ServiceHost中都是私有的。Servciehost启动的时候先检查singletonInstance是否存在,若不存在则根据serviceType反射创建一个服务实例。

    了解单例的机制需要知道一下几点: 

       1.当服务启动时候会调用服务行为(ServiceBehavior)初始化ServiceHost。而服务行为实现了IServiceBehavior接口,它定义了一个ApplyDispatchBehavior接口。

    public interface IServiceBehavior
    {
    void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters);
    void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
    void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
    }
    

     此接口的作用是将创建的实例上下文(InstanceContext)附加到终点分发器(EndpointDispatcher)的DispatchRuntime的SingletonInstance上。

       2.实例上下文提供者实现了接口IInstanceContextProvider,实例上下文提供者附加在终点分发器(EndpointDispatcher)的DispatchRuntime的InstanceContextProvider上。

    public interface IInstanceContextProvider
    {
    InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel);
    void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel);
    bool IsIdle(InstanceContext instanceContext);
    void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext);
    }
    

         当服务端接受到一个请求消息时,根据消息地址报头和Action选好终结点分发器(EndpointDispatcher)后,首先会调用终结点分发器中的运行时(DispatchRuntime)获取服务上下文提供者(IInstanceContextProvider),再调用服务上下文提供者的GetExistingInstanceContext获取InstanceContext,再从上下文中获取服务实例,调用实例的方法。流程处理完毕后调用IsIdle方法,如果返回为true则标识当前实例上下文生命周期结束,GC回收。

          上一篇介绍单调时,直接将GetExistingInstanceContext返回null,WCF会创建一个新的实例上下文,使用完毕后再调用Isdle,直接返回true,则让GC回收。因此就有了单调模型。

         实例模型只需要保证在GetExistingInstanceContext时返回一个相同的实例上下文,并且不能被GC回收,因此IsIdle返回false即可。而这个相同的实例上下文,需要到终结点分发器中取出来。

         下面自定义一个SingleServiceProvider,如前面所述,IsIdle返回false,确保不让GC回收。GetExistingInstanceContext返回内部的runtime中的SingletonInstanceContext。而这个runtime是在构造函数中指定。

    public class SingleServiceProvider : IInstanceContextProvider
        {
            private DispatchRuntime runtime;
            public SingleServiceProvider(DispatchRuntime runtime)
            {
                this.runtime = runtime;
            }
            public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
            {
                return runtime.SingletonInstanceContext;
            }
            public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
            {}
            public bool IsIdle(InstanceContext instanceContext)
            {
                return false;
            }
            public void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext)
            {}
        }
    

     自定义SingleAttribute,遍历终结点分发器,若终ServiceHost中的服务实例SingletonInstance存在,则直接获取用来构造InstanceContext;若不存在则用serviceType反射形式创建一个服务实例,再构造InstanceContext。

    public class SingleAttribute : Attribute, IServiceBehavior
        {
            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {}
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcher channel in serviceHostBase.ChannelDispatchers)
                {
                    foreach (EndpointDispatcher endpoint in channel.Endpoints)
                    {
                        DispatchRuntime runtime = endpoint.DispatchRuntime;
                        ServiceHost host = (ServiceHost)serviceHostBase;
                        object Instance = null;
                        if (null != host.SingletonInstance)
                        {
                            runtime.SingletonInstanceContext = new InstanceContext(serviceHostBase, host.SingletonInstance);
                            Instance = host.SingletonInstance;
                        }
                        else
                        {
                            Instance = Activator.CreateInstance(serviceDescription.ServiceType);
                            runtime.SingletonInstanceContext = new InstanceContext(serviceHostBase, Instance);
                        }
                        endpoint.DispatchRuntime.InstanceContextProvider = new SingleServiceProvider(runtime);
                        if (serviceDescription.ServiceType.GetInterfaces().Contains(typeof(IDisposable)))
                        {
                            FieldInfo field = typeof(ServiceHost).GetField("disposableInstance", BindingFlags.Instance | BindingFlags.NonPublic);
                            field.SetValue(host, Instance);
                        }
                       
                    }
                }
            }
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {}
        }
    

       当ServiceHost结束时会调用onClosed方法,里面会释放private的disposableInstance字段。所以这里也将创建的服务实例通过反射放到这里,这样ServiceHost关闭时也能让服务实例也能回收。

    最后使用自定义的SingleAttribute,可以看到同样实现了单例效果,并没有针对每次调用都创建一个实例上下文。

        [Single]
        public class Calculator : ICalculator,IDisposable
        {
            ......
        }    
    

     

  • 相关阅读:
    [From 11.1~11.4]事件
    [From 10.1~10.5] 对象和集合初始化器(C#语法糖系列)
    [From 9.3]out和ref关键字
    [From 8.5]转换操作符方法
    将博客搬至CSDN
    QPS 与 TPS 简介
    在cenos中,通过subversion源码进行安装
    no acceptable C compiler found in $PATH
    tgz解压
    程序中的@Override是什么意思?
  • 原文地址:https://www.cnblogs.com/lh218/p/4534506.html
Copyright © 2011-2022 走看看