程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF技術剖析之二十三:服務實例(Service Instance)生命周期如何控制[上篇]

WCF技術剖析之二十三:服務實例(Service Instance)生命周期如何控制[上篇]

編輯:關於.NET

服務調用的目的體現在對某項服務功能的消費上,而功能的實現又定義在相應的服務類型中。不論WCF服務端框架處理服務調用請求的流程有多麼復雜,最終都落實在服務實例的激活和操作方法的執行上面。WCF中的實例管理(Instance Management)旨在解決服務實例的激活和服務實例生命周期的控制。

會話(Session)的目的在於保持來自相同客戶端(服務代理)多次服務調用之間的狀態。從消息交換的角度來講,會話通過消息識別機制判斷調用某個服務的消息來源,從而將來自相同客戶端的所有消息關聯在一起。所以,會話實現了消息關聯(Message Correlation)。

實例與會話是WCF非常重要的兩個特性,它們既相對獨立,又互相制約。實例模式與對會話支持程度的不同組合,會讓最終的服務表現出截然不同的行為。對實例管理和會話的合理利用,對於改善和提高WCF服務應用的可擴展性(Scalability)、性能(Performance)、吞吐量(Throughput)等具有決定性作用。服務實例對象並不是孤立存在的,而是被封裝到一個特殊實例上下文(InstanceContext)對象之中,本系列文章從實例上下文說起。

一、實例上下文(InstanceContext)

實例上下文是對服務實例的封裝,是WCF管理服務實例生命周期的依托。我們先撇開WCF,來簡單介紹一下在托管的環境中,公共語言運行時(CLR)是如何進行托管對象的生命周期的。在一個托管應用程序中,我們通過不同的方式創建一個托管對象(比如通過new關鍵字、反射或反序列化等)時,CLR會在托管堆為該對象開辟一塊內存空間。對象的本質就是存儲於某塊內存中數據的體現,對象的生命周期終止於相應內存被回收之時。對於CLR來說,負責對托管堆(在這裡主要指GC堆)進行回收的組件是垃圾收集器(GC),GC掌握著托管對象的生殺大權,決定著托管對象的生命周期。

當GC在進行垃圾回收的時候,會將“無用”的對象標記為垃圾對象,然後再對垃圾對象進行清理。GC對“無用”對象的識別機制很簡單:判斷對象是否被“根(Root)”所引用。在這裡,“根”是對一組當前正被使用,或者以後可能被使用的對象的統稱,大體包括這樣的對象:類型的靜態字段或當前的方法參數和局部變量、CPU寄存器等。

所以,孤立存在的對象將難逃被GC回收的厄運。反之,如果希望某個對象常駐內存中,我們唯一的方式就是通過某個“根”引用該對象。本章所講的實例管理,就是對服務實例生命周期的管理,即讓服務實例按照我們希望的方式創建、存活和消亡,所以我們唯一的方式也只能是:在希望服務實例存活的時候讓它被某個“根”引用,從而阻止GC將其回收;在希望服務實例被回收的時候連“根”去除,使GC能夠將其回收。而本節所講的實例上下文(InstanceContext)就扮演著“根”的角色。

說到實例上下文,相信讀者不會感到陌生,因為在進行WCF雙向(Duplex)通信的時候,我們通過實例上下文來封裝回調對象。在WCF中,實例上下文不僅僅用於對回調對象的封裝,也用於對真正服務實例的封裝。實際上可以將WCF的雙向通信理解成一種對等通信,通信的雙方是對等的參與者,並沒有嚴格的服務端和客戶端之分,或者說通信的雙方交替地扮演著服務與客戶的角色。客戶端正常調用服務端操作是一種服務調用;服務端回調客戶端操作也可以看成是一種服務調用。因此,通過實例上下文對回調對象和服務實例進行封裝本質上是一致的。

實例上下文對服務實例的封裝大體可以通過圖1表示。一個WCF服務通過一個ServiceHost進行寄宿,並添加一到多個終結點。對於接收到的服務調用請求,如果相應的實例上下文存在,則通過它得到服務實例來處理服務請求,否則創建服務實例並通過實例上下文對其進行封裝,然後再通過實例上下文得到具體的服務實例進行服務請求處理。

圖1 實例上下文對服務實例的封裝

實例上下文通過類型System.ServiceModel.InstanceContext表示。InstanceContext繼承自CommunicationObject,實現了IExtensibleObject<InstanceContext>接口。InstanceContext的定義如下面的代碼所示:

   1: public sealed class InstanceContext : CommunicationObject, IExtensibleObject<InstanceContext>
2: {
3: //其他成員
4: public InstanceContext(object implementation);
5: public InstanceContext(ServiceHostBase host);
6: public InstanceContext(ServiceHostBase host, object implementation);
7:
8: public object GetServiceInstance();
9: public object GetServiceInstance(Message message);
10: public void ReleaseServiceInstance();
11:
12: public IExtensionCollection<InstanceContext> Extensions { get; }
13: public ServiceHostBase Host { get; }
14: public ICollection<IChannel> IncomingChannels { get; }
15: public ICollection<IChannel> OutgoingChannels { get; }
16: public SynchronizationContext SynchronizationContext { get; set; }
17: }

InstanceContext具有三個構造函數,接受ServiceHostBase對象和具體的實例對象作為其輸入參數。GetServiceInstance和ReleaseServiceInstance用戶服務實例的獲取和釋放。IncomingChannels和OutgoingChannels則表示入棧和出棧信道集合。而通過SynchronizationContext屬性則可以設置或獲取用於異步操作的同步上下文,比如服務操作須要在非UI線程下操作一個Windows Form的控件,你就需要基於UI線程的同步上下文(SynchronizationContext)。

二、實例上下文模式(InstanceContext Mode)

實例上下文模式(IntanceContext Mode)表示服務端的服務實例與客戶端的服務代理的綁定方式。如果讀者熟悉.NET Remoting,肯定會很清楚.NET Remoting具有兩種不同的遠程對象激活方式:服務端激活對象(SAO:Server Activated Object)和客戶端激活對象(CAO:Client Activated Object),而前者又具有兩種不同的變體:單調(SingleCall)和單例(Singleton)。單調模式意味著服務端對於接收到的調用,都會創建新的遠程對象,而單例模式則表示服務端使用相同的遠程對象處理來自不同客戶端的所有遠程調用。單調和單例模式體現了兩種極端的遠程對象激活方式,而CAO則是一種相對折中的方式:一個客戶端代理對象與一個遠程對象一一匹配。WCF實例上下文模式與.NET Remoting的遠程對象激活方式類似,同樣具有三種不同的實例上下文模式,分別與上述三種激活方式匹配。這三種實例上下文模式分別是:單調(Per-Call)模式、會話(Per-Session)模式和單例(Single)模式。

1、單調(Per-Call)模式

單調模式相當於.NET Remoting的SingleCall遠程對象激活方式。如果采用單調實例上下文模式,對於每一個服務調用,不論是來自相同的客戶端(服務代理)還是不同的客戶端,WCF總是創建一個全新的服務實例和實例上下文對象來處理服務調用請求。在服務操作執行完畢,實例上下文對象和被封裝的服務實例被回收調。圖2揭示了在單調模式下實例上下文、服務實例和服務代理之間的關聯。

圖2 單調模式下服務代理與服務實例上下文之間的關聯

2、會話(Per-Session)模式

會話(Session)的目的在於保持來自相同客戶端(即同一個服務代理)多次服務調用之間的狀態。如果從消息交互的角度來講,通過會話可以將來自相同客戶端的多個消息關聯在一起。在會話實例上下文模式下,WCF為每一個服務代理對象分配一個單獨的服務實例上下文對象,對於來自相同服務代理的所有服務調用請求,都將分發給相同的服務實例上下文處理。會話模式與.NET Remoting下的CAO遠程對象激活模式類似,圖3揭示了會話模式下實例上下文、服務實例和服務代理之間的關系。

圖3 會話模式下服務代理與服務實例上下文之間的關聯

3、單例(Single)模式

單例模式意味著WCF為每個服務維護一個並且僅維護一個服務實例上下文。不論請求來自相同的服務代理還是不同的服務代理,處理服務調用請求都是同一個服務實例上下文對象。單例模式相當於.NET Remoting下的Singleton遠程對象激活方式,圖4揭示了單例模式下實例上下文、服務實例和服務代理之間的關系。

clip_image008

圖4 會話模式下服務代理與服務實例上下文之間的關聯

三、 實例服務行為

在介紹服務寄宿的時候,我們談到過WCF下“契約(Contract)”和“行為(Behavior)”的區別:契約是涉及雙邊的描述(契約是服務的提供者和服務消費者進行交互的手段),那麼行為就是基於單邊的描述。客戶端行為體現的是WCF如何進行服務調用的方式,而服務端行為則體現了WCF的請求分發方式。所以服務契約會通過元數據對外發布,而服務行為則對於客戶端是透明的。

對於客戶端來講,它所關心的是通過服務調用能夠獲得正確的結果,而不會關心服務端采用怎樣的模式來激活服務實例。所以,WCF實例管理通過服務行為體現,不同的實例上下文模式通過ServiceBehaviorAttribute特性指定。在ServiceBehaviorAttribute中,通過設置InstanceContextMode屬性來指定不同的服務實例上下文模式。

   1: [AttributeUsage(AttributeTargets.Class)]
2: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
3: {
4: //其他成員
5: public InstanceContextMode InstanceContextMode { get; set; }
6: }

屬性InstanceContextMode的類型為System.ServiceModel.InstanceContextMode枚舉,三個枚舉值PerCall、PerSession和Single分別表示上述的三種實例上下文模式。默認選項為PerSession。

   1: public enum InstanceContextMode
2: {
3: PerCall,
4: PerSession,
5: Single
6: }

在本系列後續部分,我將對每一種實例模式的實現原理進行逐個剖析,相信極大的加深讀者對WCF下的服務對象生命周期管理機制的理解。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved