第一篇 《連接配置》
第二篇 《連接池》
第三篇 《標准通信》
第四篇 快速暴露接口
之前的文章,我們介紹了如何使用連接池管理Thrift節點,以及使用Thrift搭建微服務用到的標准輸入輸出。這一篇,我將介紹如何快速暴露服務接口,並對服務端進行錯誤處理。
從代碼圖上看,開發者在使用Thrift.Utility搭建微服務時,兩個類圍繞着標准輸入輸出,是最常用的兩個類,ThriftClient上一篇已經講過,用於客戶端,與服務端建立連接,並訪問服務端接口,返回值。ThriftService用於服務端,用來暴露服務接口,我們看一下ThriftService.cs:
1 public abstract class ThriftService 2 { 3 protected virtual string Excute<Q>(StandRequest<Q> request, Func<StandRequest<Q>, string> func) 4 { 5 if (request.IsValid()) 6 { 7 try 8 { 9 string result = string.Empty; 10 if (func != null) 11 { 12 result = func(request); 13 } 14 StandResponse<string> response = new StandResponse<string> 15 { 16 Code = "0", 17 Desc = "SUCCESS", 18 Data = result 19 }; 20 return SerializeHelper.JsonSerialize2(response); 21 } 22 catch (Exception ex) 23 { 24 CatchException(ex); 25 StandResponse<string> response = new StandResponse<string> 26 { 27 Code = "-2", 28 Desc = "服務端異常", 29 Data = string.Empty 30 }; 31 return SerializeHelper.JsonSerialize2(response); 32 } 33 } 34 StandResponse<string> res = new StandResponse<string> 35 { 36 Code = "-1", 37 Desc = "請求數據異常", 38 Data = string.Empty 39 }; 40 return SerializeHelper.JsonSerialize2(res); 41 } 42 43 /// <summary> 44 /// 異常處理 45 /// </summary> 46 /// <param name="ex"></param> 47 protected abstract void CatchException(Exception ex); 48 }
這個類做了兩件事,第一件事就是提供了供服務端暴露接口時使用的方法Excute(StandRequest<Q> request, Func<StandRequest<Q>, string> func),只需將得到的請求參數反序列化成StandRequest<Q>,傳入Excute,Excute將返回序列化好的響應。第二件事就是,在Excute里提供了錯誤處理機制,避免開發者進行重復的勞動,開發者只需要重寫CatchException方法。
先看一下傳統的調用一個本地的方法是怎么做的:
1 List<BrandInfo> brans = ProductService.GetBrandByVendorSysNo(32);
再看看用Thrift.Utility如何調用遠端的服務:
1 using (var tc = new ThriftClient<ProductService.Client>("ProductService")) 2 { 3 List<BrandInfo> brands = tc.Invoke<int, List<BrandInfo>>("GetBrandByVendorSysNo", 32); 4 }
很簡潔吧,如何做到的呢?
1 public class ProductServiceImpl :ThriftService, ProductService.Iface 2 { 3 public string GetBrandByVendorSysNo(string request) 4 { 5 var req = SerializationUtility.JsonDeserialize2<StandRequest<int>>(request); 6 return Excute(req, (arg) => 7 { 8 //調用Service,這是沒有使用Thrift之前的方法,通過string GetBrandByVendorSysNo(string request)將其暴露給客戶端調用,就這4、5行代碼就可以暴露一個服務接口。 9 List<BrandInfo> brans = ProductService.GetBrandByVendorSysNo(req.Data); 10 return SerializationUtility.JsonSerialize2(brans); 11 }); 12 }
14 15 protected override void CatchException(Exception ex) //開發者自己實現服務端錯誤處理 16 { 17 if (ex is BusinessException) 18 { 19 20 } 21 else 22 { 23 24 } 25 } 26 }
使用本框架,暴露服務端接口就是這么簡單。再看看客戶端的配置:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <ThriftConfig> 3 <MonitorType>Demo.RPCClient.ConnectionPoolMonitor,Demo.RPCClient</MonitorType> 4 <ServiceArray> 5 <Service Name="ProductService" IP="127.0.0.1" Port="7911" MaxActive="100" MaxIdle="20" MinIdle="10" WaitingTimeout="1000"/> 6 <Service Name="SOService" IP="127.0.0.1" Port="7912" MaxActive="100" MaxIdle="20" MinIdle="10" WaitingTimeout="1000"/> 7 </ServiceArray> 8 </ThriftConfig>
客戶端自定義模擬器示例:
1 public class ConnectionPoolMonitor:IThriftFactoryMonitor 2 { 3 public void Monitor(List<Tuple<string, int, int>> tuples) 4 { 5 foreach (var t in tuples) 6 { 7 Console.WriteLine(string.Format("自定義{0}連接池,空閑連接數量:{1},激活連接數量:{2}", t.Item1, t.Item2, t.Item3)); 8 } 9 } 10 11 public void TimeoutNotify(string serviceName, int timeOut) 12 { 13 Console.WriteLine(string.Format("自定義{0}連接池等待連接超時{1}", serviceName, timeOut)); 14 } 15 }
Demo的代碼沒有提供給大家,感興趣的可以照着示例自己寫一個。
到此整個系列就完結了,之所以寫這個系列的文章,是希望和園友們進行交流討論,如果代碼中有什么缺點或沒考慮到的地方,還希望園友們能提出來,加以改善,讓這個框架更完美。
Thrift微服務代碼下載Thrift.Utility