[老老实实学WCF] 第八篇 实例化
老老實實學WCF
第八篇 實例化
?
通過上一篇的學習,我們簡單地了解了會話,我們知道服務端和客戶端之間可以建立會話連接,也可以建立非會話連接,通信的綁定和服務協定的 ServiceContract 的SessionMode屬性共同決定了連接是否是會話的。會話連接在會話保持階段服務端可以記住客戶端,而非會話連接則不會,相同客戶端的多次調用會被 認為是不同的客戶端發起的。
?
會話這個特性是許多其他特性的基礎,例如我們今天要學習的實例化。連接是否是會話對實例化的過程將產生不同的影響。今天我們就來研究這個問題。
?
1. 什么是實例化
那么,什么是實例化呢?我們知道,要調用一個類的方法,如果這個類不是靜態類,首先要將這個類實例化從而獲得這個類的一個對象,然后在這個對象上調 用方法,這是面向對象的基本知識,而我們服務端上寄存的服務,也是一個類,是一個實現了服務接口的類,因此,客戶端在調用這個類的方法時,服務端一定也要 將這個類先實例化出一個對象,然后在這個對象上調用方法,將結果返回給客戶端。
?
我們在這里探討的實例化就是當客戶端調用服務端服務方法時,服務端如何對服務類進行實例化的問題。
2. 實例化的幾種模式
我們不禁要疑問,實例化不就是new嘛,new有什么可說的,直接實例化然后調用最后返回,這似乎沒什么特別的地方。
new的話題我覺得是個挺深的問題,它也一直是面向對象編程理論中比較重要的一環。如何正確的控制實例化的時間和地點是許多設 計模式著手解決的問題。我們在本地編程模型中不太多關注到它,可能常用的也就是為共享資源建立一個單例,或者為上層調用建立一個工廠。甚至隨用隨new的 情況也都稀松平常。
然而我們應該重視實例化的方式,尤其在面向服務這樣的模型中,實例化方式的不同會顯著的影響性能和伸縮性。
?
按照最簡單的考量,每次客戶端的方法調用服務端都實例化一個對象然后為其服務,調用完就把對象銷毀,也就是隨用隨new。這樣 看上去最簡單明了,但是性能可能不太好,創建對象和銷毀對象都是有開銷的。如果客戶端和服務端使用會話來連接,那么服務端就可以實例化一次,然后在整個會 話期間都使用這一個對象為其服務,這樣開銷就小一些了,而且客戶端是知道會話的存在的,他和服務端對于服務對象的狀態是有共識的,這樣可以重復的利用服務 對象,直到會話結束才銷毀服務對象。如果更進一步,如果創建對象的開銷太大而且對象提供的服務并沒有對不同客戶端的差異,可以讓服務端只實例化一次,這個 對象將為所有的客戶端服務,無論連接是不是會話,這個對象一直也不會被銷毀,除非服務停止或重新啟動。
?
綜上所述,服務端實例化的方式有三種,分別是"每調用實例","每會話實例"和"單一實例"。
實例化模式的指定是通過配置服務類的ServiceBehavior屬性中的InstanceContextMode屬性來實現的。注意,是服務類的屬性,而不是服務協定。
(1) 每調用實例
將服務類的ServiceBehavior屬性中的InstanceContextMode屬性設置為PerCall來啟用這種模式
在這種實例化模式下,客戶端對服務方法的每一次調用,服務端都會new一個實例,方法調用結束即銷毀,這種模式可能要頻繁的花 費創建對象和銷毀對象的花銷,因此性能比較差,但是每次調用后服務對象被銷毀,對象所把持的資源也就被釋放(如文件啦、數據庫連接啦),因此伸縮性是最好 的。
看下面的例子。
首先看加在服務類上的屬性應該怎么寫:
[csharp] view plain copy我用的還是前幾篇中用的IIS的例子,HelloWCFService.cs的源代碼如下:
[csharp] view plain copyWeb.Config文件內容如下
[html] view plain copy
調用的客戶端代碼如下:
F5運行結果如下:
可以看到,即使我們把服務協定的會話模式設置為Required(必須使用會話),即這個時候服務端和客戶端是在進行會話連接的時候,服務端還是為兩次客戶端調用分別實例化了對象,所以看到計數沒有增長,每次都是1。
?
(2) 每會話實例
將服務類的ServiceBehavior屬性的InstanceContextMode屬性設置為PerSession時啟用這種模式。
如果不指定,那么這個值是默認的配置。
這種模式下服務端在受到會話的第一個調用時實例化對象,直到會話關閉才銷毀對象,這樣減少了對象的建立和銷毀開銷,性能有一定提升,但是在會話期間申請的資源如文件和數據庫連接直到會話結束才會釋放,伸縮性有所下降了。
看看給服務類的屬性應該怎么寫:
[csharp] view plain copy其他不修改,F5運行結果如下:
可以看到計數增長了,說明沒有實例化新的對象,在整個會話中只有一個。
設想一下,如果此時把服務協定的SessionMode屬性設為NotAllowed會怎樣呢,結果會跟PerCall一樣,因為PerSession模式需要會話的支持,如果協定不支持會話,服務端就不可能記得住客戶端了,也可以理解成每次調用都是一個全新的會話了。
?
(3) 單一實例
把服務類的ServiceBehavior屬性的InstanceContextMode屬性設置為Single來啟用這種模式。
在這種模式下,服務類在受到首次調用的時候實例化,然后一直不銷毀,直到服務宿主關閉,在這期間無論是會話連接還是非會話連接,服務端都用這個實例進行調用。這樣實際上幾乎沒有創建和銷毀對象的開銷,但是如果一旦實例把持資源,則一直都不能釋放,毫無伸縮性可言。
看看服務類的ServiceBehavior屬性怎么寫:
[csharp] view plain copy其他不改動,看看運行結果。
似乎和PerSession沒有什么區別,關閉客戶端程序再運行一次,結果如下:
計數器繼續增長了,客戶端程序已經重新運行,很顯然這是個新的會話,但是服務端的實例一直沒有銷毀,所以計數器就繼續增長了。
在這種模式下,無論我們把協定的SessionMode改成什么值,結果都是一樣的,因為服務端已經認準了一個實例,無論客戶端連接是不是會話了。
3. 總結
通過今天的學習,我們了解到了服務類實例化的幾種模式,從PerCall到Single,性能越來越好,伸縮性越來越差,我們在實際項目中可以按照自己應用的特點來進行選擇,同時要注意會話模式和實例化模式之間互相的影響:
(1) 如果協定不支持會話,那么PerSession相當于PerCall。
(2) 如果服務類為PerCall,那么協定的是否支持會話結果相同。
(3) 如果服務類為Single,那么協定是否支持會話結果相同。
?
其實還有一個并發的特性,稍復雜,我們后面再展開。
轉載于:https://www.cnblogs.com/dwuge/p/5315279.html
總結
以上是生活随笔為你收集整理的[老老实实学WCF] 第八篇 实例化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [na]tcpdump参数应用参考
- 下一篇: iOS NSNotificationCe