AOP是什么?
AOP是OOP的延續,Aspect Oriented Programming的縮寫,即面向方面編程。AOP是GoF設計模式的延續,設計模式追求的是調用者和被調用者之間的解耦,AOP也是這種目標的一 種實現。
案例:在應用程序中,我們經常會對某一段程序做異常處理,或者是把一個方法的調用所消耗的時間體現在日志中,如果我們對每個方法都寫具體的實現,我想并不是一件輕松的事情。對于異常處理來講,其實我們平常編程很少去捕獲具體的異常,當然特殊程序除外,例如客戶端捕獲WCF異常時最好捕獲CommunicationException,TimeoutException,Exception。否則一般都會直接捕獲Exception,因為很多異常往往是意料之外的異常。對于記錄方法調用時間問題,我想也非常麻煩,下面例子簡單的展示了記錄時間:當你需要對多個方法都需要記錄時間時,這些代碼往往讓人感覺有重構的必要。
Stopwatch sw = new Stopwatch();
sw.Start();
//方法執行.....
sw.Stop();
WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據用時:"+sw.ElapsedMilliseconds .ToString ()+"毫秒");
上面的記錄方法調用用時,如果抽象出來,其實有下列特性:
(1)不是具體訪問類的首要或主要功能,訪問類主要功能是業務邏輯處理。
(2)具體訪問類的主要功能可以獨立、區分開來的。
(3)是這個系統的一個縱向切面,涉及多個類、多個類的方法。示意圖如下:

aspect: 新的程序結構關注系統的縱向切面,例如這里的異常處理以及方法調用時間記錄,這個新的程序結構就是aspect(方面),方面(aspect)應該有以下職責:提供一些必備的功能,對被訪問對象實現特有功能,以保證所以方法在被執行時都能正常的執行異常處理或者是其它的功能。
AOP應用范圍
(1)Authentication 權限
(2)Error handling 錯誤處理
(3)logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準
......
AOP具體實現:主要是利用泛型委托來實現AOP思想。但泛型委托有一個局限就是最多支持四個參數,當你的方法超過四個時就不太好應用AOP重構了。我最近分析了有以下三個地方我們可以對代碼進行優化:
第一:普通方法異常處理:ErrorHandler類,實現類參考第二或者是第三。
客戶端調用:
string ErrorMethodText="取積分廣場首頁酒店數據異常:";
list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList() );
第二:客戶端調用WCF的異常處理:ErrorWCFHandler。
代碼:
public class ErrorWCFHandler
{
public static void Invoke<TContract>(TContract proxy, Action<TContract> action, string MethodElapsedTimeText, string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
action(proxy);
(proxy as ICommunicationObject).Close();
}
catch (CommunicationException ex)
{
(proxy as ICommunicationObject).Abort();
//Handle Exception
//throw;
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
catch (TimeoutException ex)
{
(proxy as ICommunicationObject).Abort();
//Handle Exception
//throw;
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
catch (Exception ex)
{
//Handle Exception
//(proxy as ICommunicationObject).Close();
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
}
public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func, string MethodElapsedTimeText, string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TReturn returnValue = default(TReturn);
try
{
returnValue = func(proxy);
}
catch (CommunicationException ex)
{
(proxy as ICommunicationObject).Abort();
//Handle Exception
//throw;
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
catch (TimeoutException ex)
{
(proxy as ICommunicationObject).Abort();
//Handle Exception
//throw;
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
return returnValue;
}
}
客戶端調用:
string ComputationTimeText="取積分廣場首頁酒店數據耗時:";
string ErrorMethodText="取積分廣場首頁酒店數據異常:";
list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList
(),ComputationTimeText ,ErrorMethodText );
第三:記錄方法調用時間,這中間也增加了異常處理:ErrorAndComputationTimeHandler
代碼:
public class ErrorAndComputationTimeHandler
{
public static void Invoke<TContract>(TContract proxy, Action<TContract> action, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
action(proxy);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
}
public static void Invoke<TContract, TContract2>(TContract proxy, TContract2 proxy2, Action<TContract, TContract2> action, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
action(proxy, proxy2);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
}
public static void Invoke<TContract, TContract2, TContract3>(TContract proxy, TContract2 proxy2, TContract3 proxy3, Action<TContract, TContract2, TContract3> action, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
action(proxy, proxy2, proxy3);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
}
public static void Invoke<TContract, TContract2, TContract3, TContract4>(TContract proxy, TContract2 proxy2, TContract3 proxy3, TContract4 proxy4, Action<TContract, TContract2, TContract3, TContract4> action, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
action(proxy, proxy2, proxy3, proxy4);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
}
public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TReturn returnValue = default(TReturn);
try
{
returnValue = func(proxy);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
return returnValue;
}
public static TReturn Invoke<TContract, TContract2, TReturn>(TContract proxy, TContract2 proxy2, Func<TContract, TContract2, TReturn> func, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TReturn returnValue = default(TReturn);
try
{
returnValue = func(proxy, proxy2);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
return returnValue;
}
public static TReturn Invoke<TContract, TContract2, TContract3, TReturn>(TContract proxy, TContract2 proxy2, TContract3 proxy3, Func<TContract, TContract2, TContract3, TReturn> func, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TReturn returnValue = default(TReturn);
try
{
returnValue = func(proxy, proxy2, proxy3);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
return returnValue;
}
public static TReturn Invoke<TContract, TContract2, TContract3, TContract4, TReturn>(TContract proxy, TContract2 proxy2, TContract3 proxy3, TContract4 proxy4, Func<TContract, TContract2, TContract3, TContract4, TReturn> func, string MethodElapsedTimeText,string MethodErrorText)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TReturn returnValue = default(TReturn);
try
{
returnValue = func(proxy, proxy2, proxy3, proxy4);
}
catch (Exception ex)
{
//Handle Exception
WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
}
sw.Stop();
WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + "毫秒");
return returnValue;
}
}
客戶端調用:
string ComputationTimeText = "取酒店是否在積分廣場首頁推薦數據耗時:";
string ErrorMethodText = "取酒店是否在積分廣場首頁推薦數據異常:";
string conn = WebConfig.DaoConfig.MisMasterDBReadConnectionString;
HotelRecommendInfo = ErrorAndComputationTimeHandler.Invoke<HotelRequestInfo, string, List<HotelGenericInfo>>(requestInfo, conn, SearchRecommendHotelData, ComputationTimeText, ErrorMethodText);
AOP的優勢:
(1)上述應用范例在沒有使用AOP情況下,也能解決,但是,AOP可以讓我們從一個更高的抽象概念來理解軟件系統。可以這么說:因為使用AOP結構,對于一個大型復雜系統來說可以簡化不少代碼。
(2)并不是所有的人都需要關心AOP,使得其它開發人員有更多精力去關注自己的業務邏輯。