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

aspect: 新的程序結(jié)構(gòu)關(guān)注系統(tǒng)的縱向切面,例如這里的異常處理以及方法調(diào)用時(shí)間記錄,這個(gè)新的程序結(jié)構(gòu)就是aspect(方面),方面(aspect)應(yīng)該有以下職責(zé):提供一些必備的功能,對(duì)被訪問對(duì)象實(shí)現(xiàn)特有功能,以保證所以方法在被執(zhí)行時(shí)都能正常的執(zhí)行異常處理或者是其它的功能。
AOP應(yīng)用范圍
(1)Authentication 權(quán)限
(2)Error handling 錯(cuò)誤處理
(3)logging, tracing, profiling and monitoring 記錄跟蹤 優(yōu)化 校準(zhǔn)
......
AOP具體實(shí)現(xiàn):主要是利用泛型委托來實(shí)現(xiàn)AOP思想。但泛型委托有一個(gè)局限就是最多支持四個(gè)參數(shù),當(dāng)你的方法超過四個(gè)時(shí)就不太好應(yīng)用AOP重構(gòu)了。我最近分析了有以下三個(gè)地方我們可以對(duì)代碼進(jìn)行優(yōu)化:
第一:普通方法異常處理:ErrorHandler類,實(shí)現(xiàn)類參考第二或者是第三。
客戶端調(diào)用:
string ErrorMethodText="取積分廣場(chǎng)首頁(yè)酒店數(shù)據(jù)異常:";
list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList() );
第二:客戶端調(diào)用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;
}
}
客戶端調(diào)用:
string ComputationTimeText="取積分廣場(chǎng)首頁(yè)酒店數(shù)據(jù)耗時(shí):";
string ErrorMethodText="取積分廣場(chǎng)首頁(yè)酒店數(shù)據(jù)異常:";
list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList
(),ComputationTimeText ,ErrorMethodText );
第三:記錄方法調(diào)用時(shí)間,這中間也增加了異常處理: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;
}
}
客戶端調(diào)用:
string ComputationTimeText = "取酒店是否在積分廣場(chǎng)首頁(yè)推薦數(shù)據(jù)耗時(shí):";
string ErrorMethodText = "取酒店是否在積分廣場(chǎng)首頁(yè)推薦數(shù)據(jù)異常:";
string conn = WebConfig.DaoConfig.MisMasterDBReadConnectionString;
HotelRecommendInfo = ErrorAndComputationTimeHandler.Invoke<HotelRequestInfo, string, List<HotelGenericInfo>>(requestInfo, conn, SearchRecommendHotelData, ComputationTimeText, ErrorMethodText);
AOP的優(yōu)勢(shì):
(1)上述應(yīng)用范例在沒有使用AOP情況下,也能解決,但是,AOP可以讓我們從一個(gè)更高的抽象概念來理解軟件系統(tǒng)。可以這么說:因?yàn)槭褂肁OP結(jié)構(gòu),對(duì)于一個(gè)大型復(fù)雜系統(tǒng)來說可以簡(jiǎn)化不少代碼。
(2)并不是所有的人都需要關(guān)心AOP,使得其它開發(fā)人員有更多精力去關(guān)注自己的業(yè)務(wù)邏輯。