.NET中通過代理實(shí)現(xiàn)面向方面編程(AOP)
AOP是OOP的延續(xù),Aspect Oriented Programming的縮寫,即面向方面編程。AOP是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP也是這種目標(biāo)的一種實(shí)現(xiàn)。
我說到了在代碼中可以利用泛型委托來(lái)封裝異常處理,這樣可以讓程序看起來(lái)更加清晰,要想完成功能需要調(diào)用者調(diào)用指定的工廠方法才行,但要想改變某些程序員的編碼習(xí)慣我想是一件比較困難的事情。有朋友說利用委托來(lái)實(shí)現(xiàn)異常處理并不算是真正意義上的AOP,因?yàn)閭鹘y(tǒng)的AOP并不需要客戶端做代碼結(jié)構(gòu)的變更,最多也就是配置上的問題。但在.net中要想實(shí)現(xiàn)AOP,我想最方便的實(shí)現(xiàn)機(jī)制要屬代理機(jī)制了,但只要利用代理,在性能上就會(huì)造成一定的影響。
如果開發(fā)過分布式服務(wù),像remotion,wcf等,消息都是它們通信的重要手段??蛻舳送ㄟ^方法調(diào)用形式體現(xiàn)的服務(wù)訪問需要轉(zhuǎn)換成具體的消息,然后經(jīng)過編碼才能利用傳輸通道發(fā)送給服務(wù)端,服務(wù)執(zhí)行的結(jié)果也只能以消息的形式返回給調(diào)用方。
這些分布式服務(wù)有一共同特點(diǎn):都通過代理方法間接的調(diào)用服務(wù)。服務(wù)代理,它自身并不提供服務(wù)的實(shí)現(xiàn),只是起到一個(gè)中介作用,客戶端把服務(wù)請(qǐng)求發(fā)送給服務(wù)代理,服務(wù)代理再去調(diào)真正的服務(wù),同樣服務(wù)返回時(shí),也是返回給服務(wù)代理,再由服務(wù)代理返回給客戶端??吹竭@,我想對(duì)于實(shí)現(xiàn)AOP的攔截就有點(diǎn)眉目了。在.net中,我們可以寫自定義的RealProxy來(lái)實(shí)現(xiàn)AOP的方法攔截功能。
服務(wù)代理通常又分為以下兩種:
1:透明代理??蛻舳嗽诳缛魏晤愋偷倪h(yuǎn)程處理邊界使用對(duì)象時(shí),對(duì)對(duì)象使用的實(shí)際上是透明代理。透明代理使人以為實(shí)際對(duì)象駐留在客戶端空間中。它實(shí)現(xiàn)這一點(diǎn)的方法是:使用遠(yuǎn)程處理基礎(chǔ)結(jié)構(gòu)將對(duì)其進(jìn)行的調(diào)用轉(zhuǎn)發(fā)給真實(shí)對(duì)象。透明代理本身由 RealProxy 類型的托管運(yùn)行時(shí)類的實(shí)例收容。RealProxy 實(shí)現(xiàn)從透明代理轉(zhuǎn)發(fā)操作所需的部分功能。代理對(duì)象繼承托管對(duì)象(例如垃圾回收、對(duì)成員和方法的支持)的關(guān)聯(lián)語(yǔ)義,可以將其進(jìn)行擴(kuò)展以形成新類。這樣,該代理具有雙重性質(zhì),一方面,它需要充當(dāng)與遠(yuǎn)程對(duì)象(透明代理)相同的類的對(duì)象;另一方面,它本身是托管對(duì)象。
2:真實(shí)代理。RealProxy來(lái)實(shí)現(xiàn)與遠(yuǎn)程服務(wù)進(jìn)行通信,所以這里就是我們實(shí)現(xiàn)AOP的地方。
下圖是透明代理與真實(shí)代理以及遠(yuǎn)程對(duì)象的調(diào)用關(guān)系圖:
下圖是利用自定義的RealProxy實(shí)現(xiàn)AOP方法攔截的原理圖:
自定義異常代理類:
說明:1>自定義的代理類需要繼承RealProxy。
2>從 RealProxy 繼承時(shí),必須重寫 Invoke方法。
3>下面代碼中的LogManage是一個(gè)log4net接口,我們可以把異常統(tǒng)一記錄到日志中,供日后分析。
- /// <summary>
- /// Aspect代理,在這個(gè)類里面,實(shí)現(xiàn)對(duì)方法的攔截
- /// </summary>
- public class AspectProxyErrorLog : RealProxy
- {
- AspectManagedAttribute attr;
- /// <summary>
- /// 默認(rèn)構(gòu)造函數(shù)
- /// </summary>
- public AspectProxyErrorLog() : base()
- {
- }
- /// <summary>
- /// 構(gòu)造函數(shù)
- /// </summary>
- /// <param name="myType">被代理的類的類型</param>
- public AspectProxyErrorLog(Type myType) : base(myType)
- {
- }
- /// <summary>
- /// 構(gòu)造函數(shù)
- /// </summary>
- /// <param name="myType">被代理的類的類型</param>
- /// <param name="obj">被代理的對(duì)象</param>
- public AspectProxyErrorLog(Type myType,MarshalByRefObject obj) : base(myType)
- {
- target=obj;
- }
- MarshalByRefObject target;
- ILog LogManage;
- /// <summary>
- /// 當(dāng)在派生類中重寫時(shí),在當(dāng)前實(shí)例所表示的遠(yuǎn)程對(duì)象上調(diào)用在所提供的 IMessage 中指定的方法。<br />
- /// WebsharpAspect在這里執(zhí)行對(duì)方法執(zhí)行的攔截處理
- /// </summary>
- /// <param name="msg">IMessage,包含有關(guān)方法調(diào)用的信息。</param>
- /// <returns>調(diào)用的方法所返回的消息,包含返回值和所有 out 或 ref 參數(shù)。</returns>
- public override IMessage Invoke(IMessage msg)
- {
- IMessage retMsg=null ;
- IMethodCallMessage methodCall = (IMethodCallMessage)msg;
- IMethodReturnMessage methodReturn = null;
- object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
- methodCall.Args.CopyTo(copiedArgs, 0);
- object[] attrs = null;
- CoustomerErrorHandleAttribute ceha = null;
- if (msg is IConstructionCallMessage)
- {
- IConstructionCallMessage ccm = (IConstructionCallMessage)msg;
- RemotingServices.GetRealProxy(target).InitializeServerObject(ccm);
- ObjRef oRef = RemotingServices.Marshal(target);
- RemotingServices.Unmarshal(oRef);
- retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject)this.GetTransparentProxy());
- }
- else
- {
- IMethodCallMessage mcm = (IMethodCallMessage)msg;
- attrs = methodCall.MethodBase.GetCustomAttributes(typeof(CoustomerErrorHandleAttribute), false);
- ceha = LogManagerFactory.GetCoustomerErrorHandleAttribute(attrs, methodCall.MethodBase.Name );
- if (null != ceha)
- {
- LogManage = ceha.ILogName;
- }
- try
- {
- object returnValue = methodCall.MethodBase.Invoke(this.target, copiedArgs);
- methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
- }
- catch (Exception ex)
- {
- if (null != ex.InnerException)
- {
- methodReturn = new ReturnMessage(ex.InnerException, methodCall);
- }
- else
- {
- methodReturn = new ReturnMessage(ex, methodCall);
- }
- }
- retMsg = methodReturn;
- }
- if (null != methodReturn)
- {
- if (null != methodReturn.Exception )
- {
- if (null != this.LogManage )
- {
- this.LogManage.Error(ceha .MethodErrorText + methodReturn.Exception.ToString());
- }
- }
- }
- return retMsg;
- }
- }
延伸閱讀
面向切面編程:Aspect Oriented Programming
AOP是OOP的延續(xù),是(Aspect Oriented Programming)的縮寫,意思是面向切面編程。
主要的功能是:日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。
主要的意圖是:將日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來(lái),通過對(duì)這些行為的分離,我們希望可以將它們獨(dú)立到非指導(dǎo)業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼。
可以通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一添加功能的一種技術(shù)。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP可以說也是這種目標(biāo)的一種實(shí)現(xiàn)。
在Spring中提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。
原文標(biāo)題:.net中利用代理實(shí)現(xiàn)AOP
鏈接:http://www.cnblogs.com/ASPNET2008/archive/2010/04/25/1720820.html







51CTO技術(shù)棧公眾號(hào)

速覽