偉大的無產階級Willaim曾說過:"無論你覺得自己多麼的了不起,也永遠有人比你更強"。對,我說過!我就是william。 今天想記錄一下在項目中遇到的一個比較有意思的東西,異常攔截器(也不能完全說只是異常攔截,準確的說應該叫方法攔截),那有的人可能會說,異常攔截器不就是用Try……Catch就好了 ...
偉大的無產階級Willaim曾說過:"無論你覺得自己多麼的了不起,也永遠有人比你更強"。對,我說過!我就是william。
今天想記錄一下在項目中遇到的一個比較有意思的東西,異常攔截器(也不能完全說只是異常攔截,準確的說應該叫方法攔截),那有的人可能會說,異常攔截器不就是用Try……Catch就好了嗎?沒錯,Try……Catch是能攔截到異常。如果只是簡單攔截下,這種方法簡單可行。但是我們如果擴展下,所有的異常都要統一處理,如果你是架構師,你的團隊需要你提供一個公共的異常攔截處理組件,你會怎麼處理。
其實在做這個demo之前,我也是想了很多種處理方式,例如在方法前加特性頭使用AOP的方式,這種看的比較高大上,也需要配置大量config文件,比較複雜。也不適合我的項目現狀(實則是懶,由於框架已經基本形成,採用這種方式需要改動大量的已經完成的框架代碼,而且時間緊迫),所以放棄了。開始需求給到我時,一時之間無從下手,在網上搜羅很多處理方式,但大多數都是採用AOP加特性頭。當然我也這個demo也是藉助於博客園中各位大神的經驗。站在巨人的肩膀上,我可以看得更遠!謝謝博客園的各位博主!矯情的話不多說了直接開始我的代碼之旅。
首先我們看看效果圖,俗話說沒圖說個J8,有圖有文的才是好博文。
(這是一張執行正常的截圖)
(這是一張執行帶有異常的截圖)
(demo的結構圖,只是簡單的模擬)
解釋一下工程結構圖每隔類文件的作用。其中紅框標記的是本次的重要組件,你的攔截器中需要用他中間的介面。Castle.Core我們可以在NuGet中進行安裝。
1.【MyIntercept.cs】
這個文件就是自定義的攔截器。代碼很簡單。
1 using Castle.DynamicProxy; //必須的 2 3 4 public class MyIntercept : IInterceptor //需要實現這個介面(翻譯攔截) 5 { 6 public void Intercept(IInvocation invocation) 7 { 8 Console.WriteLine("【進入攔截器】"); 9 MethodInfo method = invocation.GetConcreteMethod();//得到被攔截的方法 10 var parameter=invocation.Arguments[0].ToString();//獲取被攔截的方法參數 11 if (!invocation.MethodInvocationTarget.IsAbstract) 12 { 13 Console.WriteLine("【被攔截的方法執行前】"+method.Name+"的參數"+ parameter); 14 15 try 16 { 17 invocation.Proceed(); 18 } 19 catch (Exception ex) 20 { 21 22 Console.WriteLine("【攔截到異常】"+ex.Message); 23 } 24 Console.WriteLine("【被攔截的方法執結果】"+invocation.ReturnValue); 25 26 } 27 Console.WriteLine("【被攔截的方法執完畢】"); 28 } 29 }View Code
2.ITestIntercept.cs】
定義一個介面,介面中定義需要實現的方法,也就是需要被攔截的方法
1 public interface ITestIntercept 2 { 3 string Test(string p); 4 }View Code
3.【TestIntercept.cs】
實現上面的介面
1 public class TestIntercept : ITestIntercept 2 { 3 public string Test(string p) 4 { 5 throw new Exception("異常了"); //演示拋出異常,攔截器是否能捕捉到異常信息 6 //return p; 7 } 8 }View Code
基本的異常攔截準備工作已經完畢,我們看看如何使用攔截器對方法進行攔截。
1 using Castle.DynamicProxy; //必須的 2 class Program 3 { 4 static void Main(string[] args) 5 { 6 MyIntercept myIntercept = new MyIntercept();//實例化攔截器 7 ProxyGenerator proxy = new ProxyGenerator(); //實例化代理 8 ITestIntercept intercept = proxy.CreateInterfaceProxyWithTarget<ITestIntercept>(new TestIntercept(),myIntercept); 9 intercept.Test("william"); 10 Console.ReadLine(); 11 } 12 }View Code
好了,一個簡單的方法攔截demo完成,他可以應用到很多場景,比如:許可權驗證,異常統計等等。
遺留問題,有興趣的同學可以試試:
1.如果介面中有多個方法,攔截器會全部攔截嗎?
2.ProxyGenerator,我才用的是CreateInterfaceProxyWithTarget對介面和實現類進行mapping。是否還有其他的方式進行mapping工作,例如配置文件?
3.本次demo中採用的是實現介面的方式對方法進行攔截,如果不用介面,攔截器是否會起作用。因為我發現在ProxyGenerator中有個CreateClassProxyWithTarget()函數。大家可以試試。