John Evdemon
Microsoft Corporation, Architecture Strategy 團(tuán)隊
適用于:
? |
企業(yè)體系結(jié)構(gòu) |
? |
面向服務(wù)的體系結(jié)構(gòu) |
? |
Web 服務(wù) |
摘要:“服務(wù)設(shè)計的原則”系列文章旨在彼此交流這方面的最佳實踐經(jīng)驗和示例代碼。本文是系列文章中的第一篇,主要提供基本的 Web 服務(wù)設(shè)計和實現(xiàn)原則,簡要介紹了“面向服務(wù)的體系結(jié)構(gòu)”(SOA) 的概念,詳細(xì)討論了開發(fā)人員在構(gòu)建 Web 服務(wù)時可以利用的幾種模式和反模式。這些原則適用于任何可以開發(fā)和部署 Web 服務(wù)的編程語言或平臺。
Microsoft Patterns & Practices 團(tuán)隊 Ron Jacobs 一篇網(wǎng)絡(luò)廣播的啟發(fā)
本文中的許多觀點和概念源自 Patterns and Practices 團(tuán)隊的 Ron Jacobs,特此感謝。2004 年底,Ron 和我基于這些內(nèi)容撰寫了一篇網(wǎng)絡(luò)廣播。如果沒有 Ron 的幫助,本文是無法完成的。
要了解關(guān)于 Ron 在 Patterns and Practices 團(tuán)隊所做工作的更多信息,請參閱 http://www.microsoft.com/resources/practices/default.mspx 和 http://www.gotdotnet.com/team/rojacobs/。
下載本文相關(guān)資料:

本頁內(nèi)容
![]() |
關(guān)于 SOA 設(shè)計原則系列文章 |
![]() |
簡介面向服務(wù)的體系結(jié)構(gòu) (SOA) |
![]() |
SOA 模式與反模式 |
![]() |
結(jié)論 |
關(guān)于 SOA 設(shè)計原則系列文章
本文是系列文章中的第一篇,集中討論如何設(shè)計更有效的 Web 服務(wù)。此開篇文章是與 Microsoft 的 patterns & practices 團(tuán)隊合作完成的,今后我們還會與 Microsoft 內(nèi)部和外部的其他團(tuán)隊和個人合作。
讀者應(yīng)慎用“SOA 設(shè)計原則系列”開發(fā)的示例代碼。示例代碼僅用于演示目的,鼓勵讀者研究、編譯和學(xué)習(xí)這些代碼。讀者應(yīng)避免在生產(chǎn)環(huán)境中嘗試使用任何示例代碼。如果讀者決定在生產(chǎn)環(huán)境中使用任何示例代碼,MICROSOFT 對其造成的損害不承擔(dān)任何責(zé)任。
示例代碼的系統(tǒng)要求:
? |
Microsoft Windows XP(示例未在其他平臺上測試) |
? |
Microsoft .NET Framework 1.1 |
? |
Microsoft Internet Information Server 6.0 |
? |
Microsoft SQL Server 或 Microsoft Access |
? |
Microsoft Visual Studio 2003 不是必需的,但如果使用會使總體效果更佳 |
雖然 Microsoft 對于示例代碼不提供支持,但本文的作者仍歡迎您給予反饋。
注意 由于 SOA 正在快速發(fā)展,隨著它的不斷成熟,本系列中的文章和示例代碼可能會有修訂。
簡介面向服務(wù)的體系結(jié)構(gòu) (SOA)
目前,SOA 已成為廣為人知而且存在些分歧的縮寫詞。如果要兩個人給 SOA 下個定義,可能會有兩個差別懸殊、甚至可能是截然對立的答案。有人將 SOA 描述為啟動業(yè)務(wù)的 IT 基礎(chǔ)結(jié)構(gòu),而其他人則認(rèn)為 SOA 可以提高 IT 的效率。在許多方面,SOA 有點像 John Godfrey Saxe 的那首盲人與象的詩:每個人對那頭象都有不同的描述,因為他們都受到了各自經(jīng)驗的影響(例如,摸到象鼻子的人認(rèn)為它是條蛇,而摸到象牙的人則認(rèn)為它是矛)。相對而言,Saxe 先生的象還是很容易描述的,因為它畢竟是真實存在的實體:而 SOA 更加難以描述,因為設(shè)計思想是無法以物理形式表現(xiàn)的。
SOA 是用于從自治服務(wù)構(gòu)建系統(tǒng)的體系結(jié)構(gòu)方法。有了 SOA,集成更具前瞻性,而不是事后反思:最終的解決方案可能由以不同編程語言開發(fā)的服務(wù)組成,由具有各種安全模型和業(yè)務(wù)流程的不同平臺托管。盡管這一概念聽起來驚人的復(fù)雜,它卻并不是新生事物:有人認(rèn)為,SOA 是從基于先前可用技術(shù)設(shè)計和開發(fā)分布式系統(tǒng)的經(jīng)驗演化而來的。與 SOA 相關(guān)的許多概念,如服務(wù)、發(fā)現(xiàn)和后期綁定,都與 CORBA 和 DCOM 有關(guān)。同樣,許多服務(wù)設(shè)計原則與早期基于封裝、抽象和定義明確的接口的 OOA/OOD 技術(shù)有著許多共同之處。
縮寫詞 SOA 提出了一個很明顯的問題:到底什么是服務(wù)?簡而言之,服務(wù)即可以通過定義明確的消息交換進(jìn)行交互的程序。服務(wù)的設(shè)計必須考慮可用性和穩(wěn)定性。服務(wù)的構(gòu)建要考量持久性,而服務(wù)配置和聚合的構(gòu)建則要考量變化性。靈活性經(jīng)常上升為 SOA 的一個最大優(yōu)勢:與受底層單一性應(yīng)用程序的約束、最小的變動也要幾個星期才能實現(xiàn)的組織相比,在松散耦合的基礎(chǔ)結(jié)構(gòu)上實現(xiàn)業(yè)務(wù)流程的組織對于變動要開放得多。松散耦合的系統(tǒng)會帶來松散耦合的業(yè)務(wù)流程,因為業(yè)務(wù)流程不再受底層基礎(chǔ)結(jié)構(gòu)局限性的約束。服務(wù)及其關(guān)聯(lián)接口必須保持穩(wěn)定,以便能夠重新配置或重新聚合來滿足日新月異的業(yè)務(wù)需求。服務(wù)的穩(wěn)定性依賴于基于標(biāo)準(zhǔn)的接口和定義明確的消息:即,用于消息定義的 SOAP 和 XML 架構(gòu)。如果服務(wù)用于執(zhí)行簡單而精確的功能、幾乎不知道消息是如何傳遞過來的或是如何檢索出來的,那么它在更大的 SOA 基礎(chǔ)結(jié)構(gòu)中被重用的可能性更大。如前所述,在我們設(shè)計和構(gòu)建可重復(fù)使用的 Web 服務(wù)時,應(yīng)當(dāng)回顧有關(guān)封裝和接口設(shè)計的 OO 設(shè)計原則。通過進(jìn)一步理解常說的面向服務(wù)的“四條原則”,我們可以將這些 OO 原則擴(kuò)展到 Web 服務(wù)領(lǐng)域。
原則 1:邊界是顯式的
通過跨越定義明確的邊界進(jìn)行顯式消息傳遞,服務(wù)得以彼此交互。有時候,跨越服務(wù)邊界可能要耗費很大的成本,這要視地理、信任或執(zhí)行因素而定。邊界是指服務(wù)的公共接口與其內(nèi)部專用實現(xiàn)之間的界線。服務(wù)的邊界通過 WSDL 發(fā)布,可能包括說明特定服務(wù)之期望的聲明。跨越邊界之所以被認(rèn)為是代價高昂的任務(wù),是有多種原因的,下面列出其中幾個:
? |
目標(biāo)服務(wù)的物理位置可能是未知的因素。 |
? |
安全和信任模型可能會在每次跨越邊界時發(fā)生改變。 |
? |
在服務(wù)的公共表示和專用表示之間封送和轉(zhuǎn)換數(shù)據(jù)可能需要依賴額外的資源:其中一些資源可能在服務(wù)之外。 |
? |
服務(wù)的構(gòu)建要考量持久性,而服務(wù)配置的構(gòu)建則要考量變化性。這一事實暗示著:由于網(wǎng)絡(luò)重新配置或者遷移到另一個物理位置,可靠的服務(wù)的性能可能會突然降低。 |
? |
服務(wù)的使用者通常不知道專用的內(nèi)部過程是如何實現(xiàn)的。特定服務(wù)的使用者對正使用的服務(wù)的性能只能進(jìn)行有限的控制。 |
面向服務(wù)的集成(英文)模式告訴我們“服務(wù)調(diào)用可能會受到網(wǎng)絡(luò)滯后、網(wǎng)絡(luò)故障和分布式系統(tǒng)故障的影響,而本地實現(xiàn)則不會。要預(yù)先考慮使用遠(yuǎn)程對象接口的影響,就必須編寫大量的錯誤檢測和更正邏輯。”盡管我們認(rèn)為跨越邊界是代價高昂的過程,但在部署用于將此類邊界跨越減至最少的本地方法時,我們還是要格外謹(jǐn)慎。實現(xiàn)單一性本地方法和對象的系統(tǒng)可能會獲得性能的改善,但功能性卻與先前定義的服務(wù)完全一樣(此項技術(shù)在 OOP 中稱為“剪切與粘貼”,同樣存在服務(wù)版本更新的風(fēng)險)。
關(guān)于第一條 SO 原則,有幾點原則需要銘記在心:
? |
弄清邊界。服務(wù)提供一個合約來定義其提供的公共接口。與服務(wù)的所有交互都通過公共接口進(jìn)行。接口由公共進(jìn)程和公共數(shù)據(jù)表示組成。公共進(jìn)程是通向服務(wù)內(nèi)部的入口點,而公共數(shù)據(jù)表示則是指該進(jìn)程使用的消息。如果我們使用 WSDL 代表一個簡單的合約,則 <message> 代表公共數(shù)據(jù),而 <portType> 代表公共進(jìn)程。文章“外部數(shù)據(jù)與內(nèi)部數(shù)據(jù)”(英文)更詳細(xì)地研究了這些問題。 |
? |
服務(wù)應(yīng)易于使用。設(shè)計服務(wù)時,開發(fā)人員應(yīng)使其易于其他開發(fā)人員使用。設(shè)計的服務(wù)接口(合約)也應(yīng)允許服務(wù)在不中斷與現(xiàn)有使用者之間的合約的情況下進(jìn)一步發(fā)展。(這一主題將在本系列的后續(xù)文章中更詳細(xì)地討論。) |
? |
避免使用 RPC 接口。應(yīng)采用顯式消息傳遞,而避免使用 RPC 之類的模型。這種方法將使用者與服務(wù)實現(xiàn)的內(nèi)部隔離開來,使開發(fā)人員可以集中精力改進(jìn)他們的服務(wù),同時將對服務(wù)使用者的影響降至最低(使用公共消息而不是公用的方法進(jìn)行封裝)。 |
? |
盡量減小服務(wù)的表面積。服務(wù)的公共接口越多,就越難以使用和維護(hù)。應(yīng)當(dāng)少提供服務(wù)的定義明確的公共接口。這些接口應(yīng)該相對簡單,主要用于接受定義明確的輸入消息并以同樣定義明確的輸出消息進(jìn)行響應(yīng)。這些接口一旦定義,即應(yīng)保持不變。這些接口提供服務(wù)必須支持的“恒定不變”的設(shè)計要求,為服務(wù)專用的內(nèi)部實現(xiàn)充當(dāng)門面。 |
? |
內(nèi)部(專用)實現(xiàn)的細(xì)節(jié)不應(yīng)泄露到服務(wù)邊界之外。如果將實現(xiàn)細(xì)節(jié)泄露到服務(wù)邊界,很可能會使服務(wù)與服務(wù)使用者之間的耦合更加緊密。服務(wù)使用者不應(yīng)當(dāng)獲知服務(wù)實現(xiàn)的內(nèi)部情況,因為這樣會使服務(wù)的版本更新或升級受到限制。本文的“反模式”部分就此問題提供了一個詳細(xì)的示例。 |
原則 2:服務(wù)具有自治性
服務(wù)是獨立進(jìn)行部署、版本控制和管理的實體。開發(fā)人員應(yīng)避免對服務(wù)邊界之間的空間進(jìn)行假設(shè),因為此空間比邊界本身更容易改變。例如,服務(wù)邊界應(yīng)當(dāng)是不變的,只有這樣才能將版本更新對使用者的影響降至最低。雖然服務(wù)邊界是相當(dāng)穩(wěn)定的,但策略、物理位置或網(wǎng)絡(luò)拓?fù)涞确?wù)部署選項卻很可能發(fā)生改變。
服務(wù)可以通過 URI 動態(tài)尋址,使其底層位置和部署拓?fù)淇梢栽趲缀醪挥绊懛?wù)本身的情況下改變或演化(服務(wù)的通信通道也是如此)。盡管這些更改對服務(wù)沒什么影響,但它們對使用服務(wù)的應(yīng)用程序卻有著破壞性的影響。如果您今天使用的服務(wù)明天被移動到新西蘭,將會怎樣呢?響應(yīng)時間的改變可能會對服務(wù)的使用者造成計劃之外或意料之外的影響。服務(wù)設(shè)計者對于服務(wù)的使用方式應(yīng)當(dāng)采取謹(jǐn)慎的態(tài)度:服務(wù)將失敗,其相關(guān)的行為(服務(wù)級別)可能會被更改。適當(dāng)級別的例外處理和補償邏輯必須與任何服務(wù)調(diào)用相關(guān)聯(lián)。此外,服務(wù)使用者可能需要修改其策略,以聲明要使用的最短服務(wù)響應(yīng)時間。例如,服務(wù)使用者可以對安全、性能、事務(wù)及許多其他因素請求不同的服務(wù)級別。可配置的策略允許單個服務(wù)支持多個有關(guān)服務(wù)調(diào)用的 SLA(而其他策略可能主要關(guān)注版本更新、本地化及其他問題)。服務(wù)級的通信性能期望始終是自治,因為服務(wù)彼此之間不需要熟悉對方的內(nèi)部實現(xiàn)。
不止是服務(wù)使用者應(yīng)該對性能采取謹(jǐn)慎的態(tài)度:服務(wù)提供者在預(yù)測其服務(wù)的使用方式時也應(yīng)同樣謹(jǐn)慎。應(yīng)該預(yù)料到服務(wù)使用者有時候會失敗,卻又不通知服務(wù)本身。服務(wù)提供者也不能信任使用者總是“為所應(yīng)為”。例如,使用者可能會嘗試使用不正常的/惡意的消息進(jìn)行通信,或者嘗試違反成功實現(xiàn)服務(wù)交互所必需的其他策略。無論用戶意圖如何,服務(wù)內(nèi)部都必須嘗試對此類不恰當(dāng)?shù)氖褂眠M(jìn)行補償。
雖然服務(wù)是自治的,但任何服務(wù)都不是孤島?;?SOA 的解決方案是不規(guī)則的,由許多為特定解決方案配置的服務(wù)組成。從自治的角度思考,您很快就會發(fā)現(xiàn)面向服務(wù)的環(huán)境中并沒有主領(lǐng)機構(gòu):編排服務(wù)中的“指揮器”概念是錯誤的(進(jìn)一步意味著,跨服務(wù)的“回滾”概念也是錯誤的:但這最好留待在另一篇文章中討論)。實現(xiàn)自治服務(wù)的關(guān)鍵是隔離和去耦合。服務(wù)都彼此獨立地設(shè)計和部署,并且只能使用合約驅(qū)動的消息和策略進(jìn)行通信。
至于其他服務(wù)設(shè)計原則,我們可以學(xué)習(xí)過去 OO 設(shè)計的經(jīng)驗。Peter Herzum 及 Oliver Sims 就 Business Component Factories 的著作提供了對自治組件特性的一些有趣見解。雖然他們大部分的工作最適于大粒度、基于組件的解決方案,但其基本設(shè)計原則仍然適用于服務(wù)設(shè)計。
鑒于這些考量,在此提供一些有助于確保符合第二條 SO 原則的簡單設(shè)計原則:
? |
服務(wù)的部署和版本控制應(yīng)獨立于部署和使用它們的系統(tǒng)。 |
? |
合約的設(shè)計應(yīng)符合以下假設(shè),即一旦公布即不可修改。這種方法迫使開發(fā)人員在其架構(gòu)設(shè)計中構(gòu)建靈活性。 |
? |
采取謹(jǐn)慎的態(tài)度,使服務(wù)免于故障。從使用者的角度,規(guī)劃服務(wù)可用性和性能的不可靠級別。從提供者的角度,預(yù)計服務(wù)會被誤用(故意或其他方式),預(yù)計服務(wù)使用者會出現(xiàn)故障:而服務(wù)可能得不到通知。 |
原則 3:服務(wù)共享架構(gòu)和合約,但不共享類
如上所述,服務(wù)交互應(yīng)當(dāng)只以服務(wù)的策略、架構(gòu)和基于合約的行為為基礎(chǔ)。服務(wù)的合約通常使用 WSDL 定義,而服務(wù)聚合的合約則可以使用 BPEL 定義(進(jìn)而,對聚合的每個服務(wù)使用 WSDL)。
大多數(shù)開發(fā)人員定義類來代表特定問題空間中的各種實體(例如,“客戶”、“訂單”和“產(chǎn)品”)。類將行為與數(shù)據(jù)(消息)組合到一個特定于編程語言或平臺的構(gòu)造函數(shù)。服務(wù)打破了這種模式,最大程度提高了靈活性和互操作性。使用基于 XML 架構(gòu)的消息進(jìn)行通信的服務(wù)獨立于編程語言與平臺,從而拓寬了互操作性的級別。架構(gòu)用于定義消息的結(jié)構(gòu)和內(nèi)容,而服務(wù)合約則用于定義服務(wù)本身的行為。
總起來說,服務(wù)的合約由以下元素組成:
? |
使用“XML 架構(gòu)”定義的消息交換格式。 |
? |
使用 WSDL 定義的“消息交換模式”(MEP)。 |
? |
使用 WS-Policy 定義的功能和要求。 |
? |
BPEL 可以用作業(yè)務(wù)流程級合約,用以聚合多個服務(wù)。 |
服務(wù)使用者將依靠服務(wù)的合約來調(diào)用服務(wù)及與服務(wù)交互。鑒于這種依賴性,服務(wù)合約必須長期保持穩(wěn)定。在利用 XML 架構(gòu) (xsd:any) 和 SOAP 處理模型(可選標(biāo)頭)的可擴(kuò)展性的同時,合約的設(shè)計應(yīng)盡可能明確。
“第三條原則”的最大挑戰(zhàn)是其持久性。服務(wù)合約一旦公布,要想修改它而又盡可能減小對現(xiàn)有服務(wù)使用者的影響,是極其困難的。內(nèi)部數(shù)據(jù)表示與外部數(shù)據(jù)表示之間的界線對于特定服務(wù)的成功部署和重用至關(guān)重要。公共數(shù)據(jù)(在服務(wù)之間傳遞的數(shù)據(jù))應(yīng)基于組織或縱向標(biāo)準(zhǔn),確保能夠跨不同服務(wù)被廣泛接受。私有數(shù)據(jù)(服務(wù)內(nèi)部的數(shù)據(jù))封裝在服務(wù)之內(nèi)。在某種程度上,服務(wù)就像是實施電子商務(wù)交易的組織的縮微代表。如同組織必須將外來采購訂單映射為其內(nèi)部 PO 格式一樣,服務(wù)也必須將通過合約達(dá)成一致的數(shù)據(jù)表示映射為其內(nèi)部格式。與前面一樣,我們可以再次使用 OO 數(shù)據(jù)封裝經(jīng)驗來闡明類似的概念:服務(wù)的內(nèi)部數(shù)據(jù)表示只能通過服務(wù)合約處理。Pat Helland 在“外部數(shù)據(jù)與內(nèi)部數(shù)據(jù)”(英文)中探討了幾個關(guān)于公共數(shù)據(jù)表示與私有數(shù)據(jù)表示的問題。
鑒于這些考量,在此提供一些有助于確保符合第三條 SO 原則的簡單設(shè)計原則:
? |
確保服務(wù)合約保持穩(wěn)定,以將對服務(wù)使用者的影響降至最低。這里的合約指公共數(shù)據(jù)表示(數(shù)據(jù))、消息交換模式 (WSDL) 和可配置的功能和服務(wù)級別(策略)。 |
? |
合約的設(shè)計應(yīng)盡可能明確,以將誤解減至最少。此外,應(yīng)通過 XML 語法和 SOAP 處理模型的可擴(kuò)展性使合約能夠適應(yīng)未來服務(wù)的版本更新。 |
? |
避免使公共數(shù)據(jù)表示與私有數(shù)據(jù)表示之間的界線混淆不清。使用者不應(yīng)看到服務(wù)的內(nèi)部數(shù)據(jù)格式,而其公共數(shù)據(jù)架構(gòu)應(yīng)不可改變(最好基于組織標(biāo)準(zhǔn)、事實標(biāo)準(zhǔn)或行業(yè)標(biāo)準(zhǔn))。 |
? |
當(dāng)不可避免要更改服務(wù)合約時,要對服務(wù)進(jìn)行版本控制。這種方法對現(xiàn)有使用者實現(xiàn)的破壞程度最小。 |
原則 4:服務(wù)兼容性基于策略
盡管它往往被認(rèn)為是最不為人所了解的原則,但對于實現(xiàn)靈活的 Web 服務(wù),它或許是最有力的。單純依靠 WSDL 無法交流某些業(yè)務(wù)交互要求。可以使用策略表達(dá)式將結(jié)構(gòu)兼容性(交流的內(nèi)容)與語義兼容性(如何交流消息或者將消息交流給誰)分隔開來。
服務(wù)提供者的操作要求可以通過計算機能識別的策略表達(dá)式來表現(xiàn)。策略表達(dá)式提供一組可以配置的可互操作語義,用以控制特定服務(wù)的行為和期望。WS-Policy 規(guī)范定義了一個計算機能識別的策略框架,它可以表達(dá)服務(wù)級策略,使它們得以在運行時被發(fā)現(xiàn)或?qū)嵤@?,政府安全服?wù)可能需要一個實施特定服務(wù)級別的策略(例如,必須對照恐怖分子識別系統(tǒng)對符合指定條件的護(hù)照像片進(jìn)行交叉檢查)。與此項服務(wù)關(guān)聯(lián)的策略信息可以用于許多與實施背景檢查有關(guān)的其他情形或服務(wù)。WS-Policy 無需任何額外代碼即可用于實現(xiàn)這些要求。本例闡明策略框架如何在提供業(yè)務(wù)定義和執(zhí)行的聲明編程模型的同時,提供有關(guān)服務(wù)要求的附加信息。
策略聲明可以確定哪些行為是策略主體的要求(或功能)。(在上面的例子中,聲明是指對照恐怖分子識別系統(tǒng)進(jìn)行背景檢查。)聲明提供特定于域的語義,并最終在各縱向行業(yè)的單獨、特定于域的規(guī)范之內(nèi)定義(建立 WS-Policy “框架”概念)。
盡管策略驅(qū)動的服務(wù)仍然在不斷發(fā)展,但開發(fā)人員仍應(yīng)確保其策略聲明在服務(wù)期望和服務(wù)語義兼容性方面盡可能明確。
SOA 模式與反模式
既然您已經(jīng)對 SOA 概念(包括 SO 設(shè)計原則)有所了解,就讓我們開始將學(xué)習(xí)到的知識付諸實踐吧。本文余下篇幅將介紹兩個“反模式”和三個“模式”。這些“反模式”和“模式”都建立在前述概念的基礎(chǔ)之上。
為什么使用模式和反模式?
人們的思考和交流往往遵循一些模式。幾部關(guān)于模式語言的書籍的作者 Christopher Alexander 將模式定義為“由在特定的非任意上下文中不斷出現(xiàn)的具體形式概括出來的抽象概念”??赏ㄟ^模式和模式語言描述最佳實踐方法、已被認(rèn)可的設(shè)計并記錄過去經(jīng)驗,在某種程度上供他人從中學(xué)習(xí)。模式是快速理解設(shè)計原則和它們所應(yīng)用的各種環(huán)境的有效方法。而如您所料,反模式與模式相對。模式提供實踐證明的指導(dǎo)原則和最佳經(jīng)驗,而反模式則闡明常見的設(shè)計缺陷,用于吸取他人的教訓(xùn)。本文余下的篇幅簡略介紹兩個反模式和三個模式,它們都可以幫助開發(fā)更有效的 Web 服務(wù)。
本文中的反模式和模式遵循下列格式:
? |
上下文:模式或反模式的簡要背景。提供上下文是為了幫助讀者在徹底實例化之前發(fā)現(xiàn)可能應(yīng)用模式或識別出反模式特征的機會。 |
? |
問題:簡單的描述,旨在制定與模式或反模式相關(guān)的目標(biāo)。 |
? |
影響因素:應(yīng)用特定模式或識別反模式時必須考慮的其他事項。 |
? |
解決方案:對特定反模式的解決方案或應(yīng)用相關(guān)模式的必要步驟的描述。 |
? |
故障現(xiàn)象與后果:對于反模式,是指導(dǎo)致反模式存在的因素。對于模式,故障現(xiàn)象與后果可以描述在應(yīng)用相關(guān)模式之前要考慮的其他因素和事項。 |
反模式中還包括關(guān)于如何改進(jìn)相關(guān)設(shè)計缺陷的其他建議。
關(guān)于代碼示例的說明
? |
每個模式的代碼示例都可以下載。 |
? |
每個示例均已包裝為安裝文件 (MSI),并且提供說明示例的安裝和配置方法的 README 文件。 |
? |
如上所述,讀者應(yīng)慎用示例代碼。示例代碼僅用于演示目的,盡管我們鼓勵讀者研究、編譯和學(xué)習(xí)這些代碼,但讀者應(yīng)避免在生產(chǎn)環(huán)境中嘗試使用任何示例代碼。如果讀者決定在生產(chǎn)環(huán)境中使用任何示例代碼,MICROSOFT 對其造成的損害不承擔(dān)任何責(zé)任。 |
反模式 1:CRUDy 接口
? |
上下文:
|
||||||
? |
問題:
|
||||||
? |
影響因素:
|
||||||
? |
解決方案:
|
代碼清單 1. Visual Basic .NET CRUD 服務(wù)示例
<WebMethod()> _ Public Sub Create( ByVal CompanyName As String, ByVal ContactName As String, ByVal ContactTitle As String, ByVal Address As String, ByVal City As String, ByVal State As String, ByVal Zip As String, ByVal Country As String, ByVal Telephone As String, ByVal Fax As String) <WebMethod()> _ Public Function MoveNext() As Boolean End Function <WebMethod()> _ Public Function Current() As Object End Function <WebMethod()> _ Public Sub UpdateContactName( ByVal NewName as String) End Sub <WebMethod()> _ Public Function CommitChanges() End Function
故障現(xiàn)象與后果:
? |
此接口設(shè)計鼓勵 RPC 形式的行為,即調(diào)用 Create、MoveNext 等等,而不是發(fā)送用于指示要采取哪些操作的定義明確的消息。這違反了第一條(定義明確的邊界)和第三條(只共享架構(gòu))原則。 |
? |
接口的通信很可能過度頻繁而瑣碎,因為使用者可能需要調(diào)用兩三個方法才能完成其工作。 |
? |
對 Create 方法使用 Sub 意味著使用者無從知道操作是成功還是失敗。設(shè)計服務(wù)時,始終要牢記使用者的期望:使用者需要知道什么? |
? |
CRUD 操作對于 Web 服務(wù)是錯誤的分解級別。CRUD 操作可以在服務(wù)內(nèi)部或不同服務(wù)之間實現(xiàn),但是不應(yīng)以這種方式提供給使用者。有些服務(wù)允許內(nèi)部(私有)功能提供給服務(wù)公共接口,這就是一例。 |
? |
此接口意味著將發(fā)生有狀態(tài)的交互,如枚舉(參見 MoveNext 和 Current 函數(shù))。 |
? |
抽象類型(如 Current 函數(shù)返回的 Object)將導(dǎo)致弱合約。這是違反第三條原則(只共享架構(gòu))的又一例。 |
? |
這是一個非常危險的服務(wù),因為它可能會使底層數(shù)據(jù)處于不一致的狀態(tài)。如果使用者添加新的“聯(lián)系人”(或者更新現(xiàn)有“聯(lián)系人”),而從不調(diào)用 CommitChanges 函數(shù),那樣會發(fā)生什么情況呢?如前所述,服務(wù)提供者不能信任使用者總是“為所應(yīng)為”。 |
按以下列方式更改服務(wù)后,可以避免上列風(fēng)險和問題:
? |
將服務(wù)接口改為使用 XML 架構(gòu)進(jìn)行通信。架構(gòu)還可以包括目標(biāo)服務(wù)操作(例如,“新建聯(lián)系人架構(gòu)”或“更改聯(lián)系人架構(gòu)”)。開發(fā)自己的架構(gòu)之前,開發(fā)人員應(yīng)參考現(xiàn)有行業(yè)標(biāo)準(zhǔn)。滿足您需要的架構(gòu)可能已經(jīng)存在。 |
? |
將數(shù)據(jù)處理封裝在私有方法之內(nèi),只能使用傳遞給公共接口的架構(gòu)訪問。 |
? |
確保服務(wù)使用者收到包含請求狀態(tài)的確認(rèn)。 |
反模式 2:Loosey Goosey
? |
上下文:
|
||||
? |
問題:
|
||||
? |
影響因素:
|
||||
? |
解決方案:
|
代碼清單 2. Visual Basic .NET 數(shù)據(jù)級服務(wù)示例
<WebMethod()> _ Public Function QueryDatabase( ByVal Database as String, SQLQuery as string) As DataSet <WebMethod()> _ Public Function Execute( ByVal Command as Integer, Arguments as string) As Boolean
故障現(xiàn)象與后果:
? |
實際上沒有合約存在。服務(wù)使用者不知道如何使用服務(wù)(例如,什么是有效的“Command”參數(shù)和編碼期望等等)。 |
? |
接口接受消息時太過自由。合約既不清晰,又存在嚴(yán)重的安全風(fēng)險,容易受到 SQL 插入代碼攻擊。 |
? |
合約沒有提供足夠的信息讓使用者知道如何使用服務(wù)。如果使用者必須讀取服務(wù)簽名之外的一些信息才能了解如何使用服務(wù),那么應(yīng)檢查服務(wù)的分解。 |
? |
使用者需要在使用 Web 服務(wù)之前熟悉數(shù)據(jù)庫和表格結(jié)構(gòu)。這將導(dǎo)致服務(wù)提供者和使用者之間發(fā)生緊耦合。 |
? |
由于依賴后期綁定和在同一服務(wù)內(nèi)邊界之間的編碼/解碼,服務(wù)的運行性能大大降低。 |
按以下列方式更改服務(wù)后,可以避免上列風(fēng)險和問題:
? |
將服務(wù)合約改為使用定義明確的 XML 架構(gòu)進(jìn)行通信。架構(gòu)不應(yīng)提供有關(guān)底層數(shù)據(jù)倉庫的任何信息。架構(gòu)的語義應(yīng)該為服務(wù)使用者提供上下文,使它們能夠了解服務(wù)的目的。(這一方法還可以提高服務(wù)的性能。) |
? |
數(shù)據(jù)庫交互應(yīng)封裝在私有方法之內(nèi),使使用者與數(shù)據(jù)庫及其關(guān)聯(lián)表格的詳細(xì)信息隔離。 |
? |
確保服務(wù)使用者收到包含請求狀態(tài)的確認(rèn)。 |
模式 1:文檔處理器
此模式的示例代碼可以下載。
? |
上下文:
|
||||||||||
? |
問題:
|
||||||||||
? |
影響因素:
|
||||||||||
? |
解決方案:
|
代碼清單 3. C# 文檔處理器服務(wù)示例
[WebMethod()] public FindCustomerByCountryResponse FindCustomersByCountry( FindCustomerByCountry request) { ... }
故障現(xiàn)象與后果:
使用此簡單模式定義的服務(wù)將符合 SO 設(shè)計原則:
? |
以文檔為中心的 Web 服務(wù)更容易映射到業(yè)務(wù)流程,因為使用者往往將業(yè)務(wù)流程看成發(fā)送和接收文檔(注意,文檔可能代表業(yè)務(wù)事件,而不是實際的業(yè)務(wù)文檔)。 |
? |
服務(wù)邊界相當(dāng)于在公共數(shù)據(jù)表示與私有數(shù)據(jù)表示之間進(jìn)行轉(zhuǎn)換時的清晰界線。 |
? |
服務(wù)的實現(xiàn)細(xì)節(jié)被封裝起來,不讓使用者知悉。 |
? |
采取“合約至上”方法有助于確保服務(wù)的高度可互操作性。 |
? |
以文檔為中心的服務(wù)易于改進(jìn),因為所有交互都通過消息發(fā)生,而不是通過硬編碼的 RPC 方法。 |
對于此方法,有一些小問題應(yīng)該注意:
? |
對于從內(nèi)部表示到外部表示的數(shù)據(jù)傳輸,性能可能會成為一個問題。 |
? |
服務(wù)使用者必須將其數(shù)據(jù)表示映射到服務(wù)使用的架構(gòu)。某些使用者可能會發(fā)現(xiàn)映射到服務(wù)架構(gòu)是一個得不償失的過程。 |
模式 2:冪等消息
此模式的示例代碼可以下載。
? |
上下文:
|
||||||||||||||
? |
問題:
|
||||||||||||||
? |
影響因素:
|
||||||||||||||
? |
解決方案:
|

圖 1. 冪等消息模式
? |
故障現(xiàn)象與后果: 冪等消息傳送是一個棘手的問題。處理重復(fù) UOW ID 有三個選項,對其中的每個選項都有若干要考慮的地方:
UOW ID 應(yīng)該是請求架構(gòu)的組成部分,將重復(fù)請求綁定到相關(guān)業(yè)務(wù)流程中。UOW ID 也可能是作為自定義 SOAP 標(biāo)頭添加的,從而使重復(fù)處理成為總體消息處理基礎(chǔ)結(jié)構(gòu)的組成部分。使用者的 URI 也應(yīng)包括在內(nèi),以幫助檢測重入??梢宰詣泳S護(hù)修改的審核追蹤,使修改請求跟蹤能夠返回給定的 UOW ID。最后,與緩存“刷新”關(guān)聯(lián)的問題可以通過反映收到請求時的響應(yīng)來解決。緩存管理是超出本文范圍的又一個難題。(建議有興趣詳細(xì)了解緩存問題的讀者查看 MSDN 文章并發(fā)處理:設(shè)計服務(wù)與其代理之間的交互(英文)。 由于服務(wù)不再相信使用者能“為所應(yīng)為”,故支持冪等消息傳送提高了服務(wù)自治性(第一條設(shè)計原則)。對于此方法,有一些小問題應(yīng)該注意: |
||||||||||||
? |
使用此模式的服務(wù)將有可能使用大容量持久存儲,以滿足響應(yīng)的緩存需求。 |
||||||||||||
? |
由于管理緩存,可能會對服務(wù)性能造成嚴(yán)重影響。 |
模式 3:預(yù)訂
此模式的示例代碼可以下載。
? |
上下文:
|
||||||||||||||||
? |
問題:
|
||||||||||||||||
? |
影響因素:
|
||||||||||||||||
? |
解決方案:
|

圖 2. 預(yù)訂模式
? |
故障現(xiàn)象與后果:
|
“預(yù)訂 ID”和過期時間戳應(yīng)該是“確認(rèn)請求”架構(gòu)的一部分,將預(yù)訂處理綁定到實際業(yè)務(wù)過程中。服務(wù)為每個預(yù)訂請求生成“預(yù)訂 ID”和過期時間戳,使服務(wù)能夠定期檢查未確認(rèn)的預(yù)訂并使其“過期”。此模式可以與“冪等消息”模式組合,進(jìn)而將服務(wù)與重復(fù)的預(yù)訂請求隔離。
對于此方法,有一些小問題應(yīng)該注意:
? |
處理預(yù)訂請求的業(yè)務(wù)規(guī)則必須定義清晰。將如何處理“預(yù)訂超量”? |
? |
我們有點被原子兩段提交模型擾亂了,常常試圖將其應(yīng)用于不很適合的場合(例如,運行時間長的過程)。運行時間長的過程必須保持組成它們的原子過程的一致性。運行時間長的過程中的工作隔離不是件簡單的事情,像“預(yù)訂”這樣的模式是解決此問題的簡單嘗試。 |
結(jié)論
四條“面向服務(wù)”原則提供了一組分立的基本原則,可用于指導(dǎo)服務(wù)開發(fā)工作。本文提供了幾個模式和反模式,旨在說明這些原則如何影響服務(wù)設(shè)計。我們還提供了一些其他準(zhǔn)則,用于幫助確保您將來的服務(wù)設(shè)計和開發(fā)工作獲得成功:
? |
分解服務(wù)時,根據(jù)現(xiàn)有文檔和已知業(yè)務(wù)事件為業(yè)務(wù)過程建模。 |
? |
雖然服務(wù)接口靈活很重要,但要避免太過靈活,以防底層服務(wù)合約變得不清晰。 |
? |
不要期望服務(wù)使用者“為所應(yīng)為”。如果服務(wù)要求使用者以預(yù)先定義好的方式執(zhí)行一系列步驟,請借助于模式(例如,預(yù)訂)幫助強制執(zhí)行這些步驟。 |
? |
永遠(yuǎn)不要使服務(wù)或其關(guān)聯(lián)資源處于不一致的狀態(tài)。 |
還有許多其他設(shè)計問題與 Web 服務(wù)關(guān)聯(lián)。本系列的后續(xù)文章將討論諸如版本控制、服務(wù)分解和策略驅(qū)動的服務(wù)配置等問題。
轉(zhuǎn)到原英文頁面
原文地址:http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/SOADesign.mspx?mfr=true