.NET應用架構設計—面向查詢服務的參數化查詢設計(分解業務點,單獨配置各自的數據查詢契約)


閱讀目錄:

  • 1.背景介紹
  • 2.對業務功能點進行邏輯划分(如:A、B、C分別三個業務點)
    • 2.1.配置映射關系,對業務點配置查詢契約(構造VS插件方便生成查詢契約)
    • 2.2.將配置好的映射策略文件放在調用端,與服務不耦合
  • 3.Dynamic、Dom動態構造服務端對象(Dynamic、DOM實現動態DOM)

1.背景介紹

現在越來越多的公司都在嘗試SOA架構的實踐,本人最近也在嘗試學習這方面的技術,但是在實踐過程中遇到一個問題,我想這個問題也是我們普遍實踐者都應該會遇到的問題,問題描述如下:

我們有一個SOA商品(Item)查詢接口,這個接口很通用,主要用來支撐日常很多其他系統的大量關於Item的查詢,尤其是在高峰期間該服務的壓力是很大的;我們站在SOA的角度看這個接口,這個通用的接口解決了眾多的查詢業務,確實不錯,但是我們切換一下角度,站在每一個調用接口的訪問端看似乎並不是很滿意或者說犧牲了部分性能上的代價,因為我們無法干凈利落的只獲取當前這個業務點需要的數據項;這個Item服務接口所返回的數據項必須同時滿足所有調用它的業務點,哪怕這次調用我只需要用到Item的三分之一的數據字段都不行,每次都會把不需要的字段都查詢出來,不管是返回的性能、查詢的性能,其實都是可以通過調整設計來避免的;

(查看大圖)

以往我們的思路都是集中在服務端,常規做法都是提供了一個能夠容納所有查詢客戶端需求的數據實體,客戶端可選擇的余地很有限,無法只獲取自己所需要的幾個數據項,甚至各個業務點在不同的情況下都有可能需要兩到三個數據返回實體;總而言之,面向數據查詢的服務接口如果要向着SOA方向發展那就必須包含SOA設計上的相關原則,如這里的面向查詢為主的服務設計其實就是缺少SOA原則中的”服務應具有策略性“一原則;

為什么以往一直沒有暴露出這個問題呢,是因為以往都是在本地直接調用“查詢引擎”,如:SQLSERVER,在“查詢引擎”的最后一層就是應用程序,而應用程序中可以編寫很多彼此類似的查詢方法,每個方法可能只有一兩個字段的差異性,或者通過“企業應用架構模式—查詢對象模式”來將不同的方法合在一起通過一個可以調整查詢字段的對象來配置本次需要的查詢字段;由於現在我們已將查詢服務化,就不太可能再去為了所有客戶端在去適應性的去擴充類似沒有太大價值的接口,但是客戶端又需要將自己所需要的查詢字段讓服務知道,所以這里的解決方案可以稱為面向SOA的”企業應用架構模式—查詢對象模式“

本文將通過運用”關注點分離“通用設計思想來對查詢服務在服務端的強耦合進行分解,將強耦合從服務端遷移出來通過策略性的配置將關注點放入各自的客戶端,從而有效的解決服務不再臃腫的問題,如果理解上有困難可以嘗試使用面向SOA的”企業應用架構模式—查詢對象模式“概念來理解;

2.對業務功能點進行邏輯划分(如:A、B、C分別三個業務點)

首先我們需要將相對於服務來說的客戶端中所有業務點進行邏輯划分,將原本一個高耦合的龐大數據實體分解成各自所需要的一個精簡的數據實體;業務點的划分目地在於可以將數據實體能與之對應起來,這個數據實體是針對於查詢服務而言的,對於客戶端來說沒有任何的依賴和約束,也就是說本次業務點發起的查詢將把這個數據實體轉化成一組查詢策略中的設置帶到服務端中,然后服務端在根據這組策略信息進行組合最終的查詢語句;

注:這里的數據實體並不是服務端定義的DTO,也不是客戶端定義的DTO,而是一個只跟本次業務查詢相關的數據查詢實體,該實體不是一個定義的類,而是一個策略,類似:

A.Business{Query field{ItemNumber、Description、PromationPrice}}

這樣一組配置信息;客戶端用來反序列化的DTO可以是一個龐大的共用的數據實體,也可以是跟業務點綁定的精簡實體,對於查詢沒有任何影響,我們要解決的是“只查詢我所需要的數據項,只返回我所需要的數據項”,而跟你在服務端、客戶端定義的用來輔助序列化的實體沒有任何關系;

 (查看大圖)

將查詢的字段、返回的字段通過查詢策略帶入到服務端,我們就能夠知道本次業務點查詢的是需要什么樣的字段,然后就可以在構造查詢引擎參數時將返回的字段直接加上或者過濾不需要的;

2.1.配置映射關系,對業務點配置查詢契約(構造VS插件方便生成查詢契約)

將系統中需要調用服務接口的所有功能點進行業務點邏輯划分設計后,每個業務點都需要在自己發起調用服務的時候能夠帶上在之前某個時間點設計好的查詢契約,這個用來生成查詢契約的工具最好是集成在VisualStudio中的自定義插件,在設計時用來動態構造一個對應的契約配置文件,如果可以的話可以采用動態代碼方案,將配置文件的靜態文件通過動態生成代碼的方式嵌入到生成的代碼中去,減少不需要的配置文件,也減少查詢框架的性能開銷,一次生成后就可以直接使用;

2.2.將配置好的映射策略文件放在調用端,與服務不耦合

本篇文章的解決方案最大的突破點就是將關注點從服務端轉移到所有客戶端上,將原本都集中在服務上的所有客戶端的需求分離出去,每個需要調用服務的客戶端維護好自己的一份查詢契約,在每次調用服務的時候帶上那份契約;如果處於性能考慮每次帶上契約會增加開銷,那么可以在第一次身份驗證的時候在服務上確認,以后調用都忽略;

這樣一來服務將精簡很多,通過同樣的設計方法可以用來設計很多類似的服務接口,將關注點從服務上轉移到客戶端上,會是一個很好的設計思路;

3.Dynamic、Dom動態構造服務端對象(Dynamic、DOM實現動態DOM)

借助C#新特性Dynamic,我們可以在.NET平台上進行動態編程,這里可以解決我們預先定義服務端實體的好處;以往我們需要在服務上定義一個至少能容納所有客戶端查詢契約中的所有數據項的實體,但是當我們運用動態編程時,我們無需事先定義一個類,而可以在運行時動態獲取對象屬性,當然這得益於.NETDLR的實現;再適當的結合DOM思想,我們就可以實現一個動態DOM效果,對於DOM的某個Element的訪問也無需定義映射實體然后在通過屬性獲取,中間既增加了序列化的開銷還增加了開發工作量;

 1 using System;
 2 using System.Collections.Generic; 
 3 
 4 namespace ConsoleApplication1.DynamicDom
 5 {
 6     public class ItemEntity : System.Dynamic.DynamicObject
 7     {
 8         /// <summary>
 9         /// 可以使用LINQ TO XML或者將XML數據構造在一個指定的容器中,用來判斷是否存在
10         /// </summary>
11         private static Dictionary<string, object> itemPropery = new Dictionary<string, object>();
12         static ItemEntity()
13         {
14             itemPropery.Add("ItemNumber", 1029394);
15             itemPropery.Add("PromationPrice", 100);
16         }
17         public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
18         {
19             if (itemPropery.ContainsKey(binder.Name))
20             {
21                 result = itemPropery[binder.Name];
22                 return true;
23             }
24             result = null;
25             return false;
26         }
27     }
28 } 
1 dynamic itemEntity = new DynamicDom.ItemEntity();
2 Console.WriteLine("ItemNumber:" + itemEntity.ItemNumber);
3 Console.WriteLine("PromationPrice:" + itemEntity.PromationPrice);
4 Console.ReadLine(); 

這里只是一個簡單的示例,目的是想讓並不太了解Dynamic的朋友有了直觀上的認識;通過使用Dynamic、Dom可以在服務端上無需定義任何的實體,根據各個客戶端傳過來的配置直接進行動態訪問,可以借助LIQN TO XML;

全文僅僅是一個設計上的介紹,要想完全實現上面這些效果需要還是需要開發些東西的,這里只是拋磚引玉,希望對正在設計相關內容的朋友提供一個思路;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM