第一篇 《連接配置》
第二篇 《連接池》
第三篇 《標准通信》
第四篇 快速暴露接口
之前的文章,我們介紹了如何使用連接池管理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
