日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

【转】在.Net中关于AOP的实现

發(fā)布時(shí)間:2023/12/2 asp.net 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】在.Net中关于AOP的实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:http://www.uml.org.cn/net/201004213.asp

一、AOP實(shí)現(xiàn)初步

AOP將軟件系統(tǒng)分為兩個(gè)部分:核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)。核心關(guān)注點(diǎn)更多的是Domain Logic,關(guān)注的是系統(tǒng)核心的業(yè)務(wù);而橫切關(guān)注點(diǎn)雖與核心的業(yè)務(wù)實(shí)現(xiàn)無(wú)關(guān),但它卻是一種更Common的業(yè)務(wù),各個(gè)關(guān)注點(diǎn)離散地分布于核心業(yè)務(wù)的多處。這意味著,如果不應(yīng)用AOP,那么這些橫切關(guān)注點(diǎn)所代表的業(yè)務(wù)代碼,就會(huì)分散在系統(tǒng)各處,導(dǎo)致系統(tǒng)中的每個(gè)模塊都與這些業(yè)務(wù)具有很強(qiáng)的依賴(lài)性。在這里,所謂橫切關(guān)注點(diǎn)所代表的業(yè)務(wù),即為“方面(Aspect)”,常見(jiàn)的包括權(quán)限控制、日志管理、事務(wù)處理等等。

?????????????????????????

以權(quán)限控制為例,假設(shè)一個(gè)電子商務(wù)系統(tǒng),需要對(duì)訂單管理用戶(hù)進(jìn)行權(quán)限判定,只有系統(tǒng)用戶(hù)才能添加、修改和刪除訂單,那么傳統(tǒng)的設(shè)計(jì)方法是:

public class OrderManager

{

private ArrayList m_Orders;

public OrderManager()

{

?????? m_Orders = new ArrayList();

}

public void AddOrder(Order order)

{

??? if (permissions.Verify(Permission.ADMIN))

??? {

????????????? m_Orders.Add(order);

??? }

}

public void RemoveOrder(Order order)

{

??? if (permissions.Verify(Permission.ADMIN))

??? {

????????????? m_Orders.Remove(order);

??? }

}

}

這樣的設(shè)計(jì)其缺陷是將訂單管理業(yè)務(wù)與權(quán)限管理完全結(jié)合在一起,耦合度高。而在一個(gè)系統(tǒng)中,類(lèi)似的權(quán)限控制會(huì)很多,這些代碼就好像一顆顆毒瘤一般蔓延于系統(tǒng)中的各處,一旦需要擴(kuò)展,則給程序員們帶來(lái)的困難是不可估量的。

?????????????????????????

讓我們來(lái)觀察一下訂單管理業(yè)務(wù)中的權(quán)限管理。不管是添加訂單,還是刪除訂單,有關(guān)權(quán)限管理的內(nèi)容是完全相同的。那么,為什么我們不能將這些相同的業(yè)務(wù),抽象為一個(gè)對(duì)象,并將其從訂單管理業(yè)務(wù)中完全剝離出來(lái)呢?在傳統(tǒng)的OO設(shè)計(jì)思想,這種設(shè)想是不能實(shí)現(xiàn)的。因?yàn)橛唵喂芾順I(yè)務(wù)作為一個(gè)類(lèi)對(duì)象,它封裝了諸如添加、刪除訂單等行為。這種封裝性,就決定了我們不可能切入到對(duì)象內(nèi)部,通過(guò)獲取方法消息的形式,對(duì)對(duì)象行為進(jìn)行監(jiān)控與操作。

?????????????????????????

AOP的思想解決了這個(gè)問(wèn)題,之所以稱(chēng)為“方面(Aspect)”,就是把這些對(duì)象剖開(kāi),僅獲取其內(nèi)部相一致的邏輯,并剝離出來(lái),以“方面”的形式存在。要讓這些方面能夠?qū)诵臉I(yè)務(wù)進(jìn)行控制,就需要有一套獲取方法消息的機(jī)制。在.Net中,其中一種技術(shù)稱(chēng)為動(dòng)態(tài)代理。

?????????????????????????

在.Net中,要實(shí)現(xiàn)動(dòng)態(tài)代理,需要用到.Net Remoting中的消息機(jī)制,以及.Net Framework內(nèi)部提供的ContextAttribute類(lèi)來(lái)自定義自己的Attribute。另外,.Net還要求調(diào)用“Aspect”的核心業(yè)務(wù)類(lèi),必須繼承ContextBoundObject類(lèi)。只有這樣,我們才能截取其內(nèi)部傳遞的方法消息。以下,是相關(guān)接口和類(lèi)的說(shuō)明。

ContextAttribute類(lèi)?????????????????????????? ????????????????????????

該類(lèi)繼承了Attribute類(lèi),它是一個(gè)特殊的Attribute,通過(guò)它,可以獲得對(duì)象需要的合適的執(zhí)行環(huán)境,即Context(上下文)。它還實(shí)現(xiàn)了IContextAttribute和IContextProperty接口。我們自定義的Attribute將從ContextAttribute類(lèi)派生。

構(gòu)造函數(shù):?????????????????????????? ????????????????????????

ContextAttribute類(lèi)的構(gòu)造函數(shù)帶有一個(gè)參數(shù),用來(lái)設(shè)置ContextAttribute的名稱(chēng)。?????????????????????????? ????????????????????????

公共屬性:?????????????????????????? ????????????????????????

Name:只讀屬性。返回ContextAttribute的名稱(chēng)?????????????????????????? ????????????????????????

公共方法:?????????????????????????? ????????????????????????

GetPropertiesForNewContext:虛擬方法。向新的Context添加屬性集合。?????????????????????????? ????????????????????????

IsContextOK虛擬方法。查詢(xún)客戶(hù)Context中是否存在指定的屬性。?????????????????????????? ????????????????????????

IsNewContextOK虛擬方法。默認(rèn)返回true。一個(gè)對(duì)象可能存在多個(gè)Context,使用這個(gè)方法來(lái)檢查新的Context中屬性是否存在沖突。?????????????????????????? ????????????????????????

Freeze:虛擬方法。該方法用來(lái)定位被創(chuàng)建的Context的最后位置。?????????????????????????? ????????????????????????

?????????????????????????

ContextBoundObject類(lèi)?????????????????????????? ????????????????????????

這個(gè)類(lèi)的對(duì)象通過(guò)Attribute來(lái)指定它所在的Context,凡是進(jìn)入該Context的調(diào)用都可以被攔截。該類(lèi)從MarshalByRefObject派生。?????????????????????????? ????????????????????????

?????????????????????????

IMessage:定義了被傳送的消息的實(shí)現(xiàn)。一個(gè)消息必須實(shí)現(xiàn)這個(gè)接口。?????????????????????????? ????????????????????????

?????????????????????????

IMessageSink:定義了消息接收器的接口,一個(gè)消息接收器必須實(shí)現(xiàn)這個(gè)接口。

該接口主要提供了兩個(gè)方法,分別進(jìn)行同步和異步操作:

SyncProcessMessage(IMessage msg):接口方法,當(dāng)消息傳遞的時(shí)候,該方法被調(diào)用;

AsyncProcessMessage(IMessage msg, IMessageSink replySink):該方法用于異步處理;

?????????????????????????

下面是實(shí)現(xiàn)權(quán)限控制AOP的簡(jiǎn)單實(shí)現(xiàn),首先我們自定義一個(gè)Attribute,它繼承了ContextAttribute:

[AttributeUsage(AttributeTargets.Class)]?????????????????????????????? ????????????????????????

??? public class AOPAttribute:ContextAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? public AOPAttribute()?????????????????????????????? ????????????????????????

??????????? : base("AOP")?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? ctorMsg.ContextProperties.Add(new AOPProperty());?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }

在GetPropertiesForNewContext()方法中,添加了AOPProperty對(duì)象,它是一個(gè)上下文環(huán)境屬性:

??? public class AOPProperty : IContextProperty, IContributeObjectSink???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? public AOPProperty()?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #region IContributeObjectSink Members?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return new AOPSink(nextSink);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

?????????????????????????

??????? #region IContextProperty Members?????????????????????????????? ????????????????????????

?????????????????????????

??????? public void Freeze(Context newContext)?????????????????????????????? ????????????????????????

??????? {??????????? ?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public bool IsNewContextOK(Context newCtx)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return true;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public string Name?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? get { return "AOP"; }?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #endregion

AOPProperty屬性實(shí)現(xiàn)了接口IContextProperty,IContributeObjectSink。GetObjectSink()方法為IContributeObjectSink接口的方法,在其實(shí)現(xiàn)中,創(chuàng)建了一個(gè)IMessageSink對(duì)象AOPSink,該對(duì)象實(shí)現(xiàn)了IMessageSink接口:

??? public class AOPSink : IMessageSink???????????????????????????????? ????????????????????????

??? {??????? ?????????????????????????????? ????????????????????????

??????? private IMessageSink m_NextSink;?????????????????????????????? ????????????????????????

?????????????????????????

?? ?????public AOPSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? m_NextSink = nextSink;?????????? ?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessageSink NextSink?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? get { return m_NextSink; }?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessage SyncProcessMessage(IMessage msg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? IMethodCallMessage call = msg as IMethodCallMessage;?????????????????????????????? ????????????????????????

??????????? if (call == null)?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? return null;?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

IMessage retMsg = null;?????????????????????????????? ????????????????????????

if (call.MethodName == "AddOrder" || call.MethodName == "DeleteOrder")?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? if (permissions.Verify(Permission.ADMIN))?????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

????????? retMsg = m_NextSink.SyncProcessMessage(msg);?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?? ?????????????????????????????????????? ????????????????????????

??????????? return retMsg;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return null;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }

在AOPSink中,最重要的是SyncProcessMessage()方法,在這個(gè)方法中,實(shí)現(xiàn)了權(quán)限控制,并通過(guò)IMessage,截取了需要權(quán)限控制的方法。在檢驗(yàn)了權(quán)限之后,然后再執(zhí)行OrderManager的AddOrder和DeleteOrder方法。

?????????????????????????

通過(guò)AOP的實(shí)現(xiàn),原來(lái)的OrderManager,就可以修改為:

[AOP]?????????????????????????????? ????????????????????????

public class OrderManager: ContextBoundObject

{

private ArrayList m_Orders;

public OrderManager()

{

?????? m_Orders = new ArrayList();

}

public void AddOrder(Order order)

{

??? m_Orders.Add(order);

}

public void RemoveOrder(Order order)

{

??? m_Orders.Remove(order);

}

}

在上述的OderManager類(lèi)中,完全消除了permissions.Verify()等有關(guān)權(quán)限的代碼,解除了訂單管理與權(quán)限管理之間的耦合。

?????????????????????????

二、與AspectJ比較?????????????????????????? ????????????????????????

上述的方案雖然解除了訂單管理與權(quán)限管理的耦合,但從SyncProcessMessage()方法可以看出,它的實(shí)現(xiàn)具有很大的局限性。試想一下這樣的應(yīng)用場(chǎng)景,在訂單管理系統(tǒng)中,用戶(hù)要求對(duì)修改訂單的方法增加權(quán)限驗(yàn)證,同時(shí)要求在驗(yàn)證權(quán)限時(shí),允許業(yè)務(wù)經(jīng)理(Permission.Manager)也具備管理訂單的權(quán)限,應(yīng)該怎樣做?仔細(xì)思考,我們會(huì)發(fā)覺(jué)以上的實(shí)現(xiàn)未免太過(guò)死板了。

?????????????????????????

讓我們來(lái)參考一下AspectJ在java中的實(shí)現(xiàn)。AspectJ提供了自己的一套語(yǔ)法,其中包括aspect、pointcut、before、after等。我們可以通過(guò)aspect定義一個(gè)“方面”,如上的權(quán)限管理:

private static aspect AuthorizationAspect{……}

?????????????????????????

pointcut為切入點(diǎn),在其中定義了需要截取上下文消息的方法,例如:

private pointcut authorizationExecution():

execution(public void OrderManager.AddOrder(Order)) ||

execution(public void OrderManager.DeleteOrder(Order)) ||

execution(public void OrderManager.UpdateOrder(Order));

?????????????????????????

由于權(quán)限驗(yàn)證是在訂單管理方法執(zhí)行之前完成,因此在before中,定義權(quán)限檢查:

before(): authorizationExecution()

{

if !(permissions.Verify(Permission.ADMIN))

{

??? throw new UnauthorizedException();

}

}

從上述AspectJ的實(shí)現(xiàn)中,我們可以看到,要定義自己的aspect是非常容易的,而通過(guò)pointcut的方式,可以將需要截取消息的方法,集中在一起。before和after則是具體的方面執(zhí)行的邏輯,它們就好像Decorator模式那樣,對(duì)原有方法進(jìn)行了一層裝飾,從而達(dá)到將aspect代碼植入的目的。

?????????????????????????

另外,AspectJ還提供了更簡(jiǎn)單的語(yǔ)法,可以簡(jiǎn)化前面pointcut中一系列方法的列舉:

private pointcut authorizationExecution():

execution (public * OrderManager.*(.))

?????????????????????????

AspectJ在應(yīng)用AOP領(lǐng)域,已經(jīng)非常成熟。它提供了自成一體的特有AspectJ語(yǔ)法,并需要專(zhuān)門(mén)的java編譯器,使用起來(lái)較為復(fù)雜。那么,在.Net下,可否實(shí)現(xiàn)類(lèi)似AspectJ的功能呢?我想,由于.Net與java在很多技術(shù)的相似性,它們彼此之間在很多領(lǐng)域是相通的,因此要達(dá)到這一目標(biāo)應(yīng)該是可行的。事實(shí)上,開(kāi)源項(xiàng)目中的Aspect#,就與AspectJ相似。

?????????????????????????

事實(shí)上,如果我們利用前面描述的動(dòng)態(tài)代理機(jī)制,輔以設(shè)計(jì)模式的OO設(shè)計(jì)方法,直接在代碼中也可以實(shí)現(xiàn)AspectJ中的部分AOP特性。

?????????????????????????

三、.Net中AOP的深入實(shí)現(xiàn)?????????????????????????? ????????????????????????

我們先分析AspectJ中的pointcut和.Net中的SyncProcessMessage()方法。Pointcut可以添加一系列需要截取上下文的方法,那么在.Net中,我們也可以利用集合,動(dòng)態(tài)地添加方法,并創(chuàng)建這些方法與“方面”的映射。同樣的,AspectJ中的before和after,是“方面”的核心實(shí)現(xiàn),那么在.Net中,我們也可以利用委托,使其對(duì)應(yīng)相關(guān)的方法,來(lái)實(shí)現(xiàn)其核心邏輯。

?????????????????????????

結(jié)合動(dòng)態(tài)代理的知識(shí),我們先定義兩個(gè)委托,分別代表before和after操作:

public delegate void BeforeAOPHandle(IMethodCallMessage callMsg);?????????????????????????????? ????????????????????????

public delegate void AfterAOPHandle(IMethodReturnMessage replyMsg);

?????????????????????????

BeforeAOPHandle中的參數(shù)callMsg,其值為要截取上下文的方法的消息;AfterAOPHandle中的參數(shù)replyMsg,則是該方法執(zhí)行后返回的消息。

?????????????????????????

接下來(lái),定義一個(gè)抽象基類(lèi)AOPSink,它實(shí)現(xiàn)了IMessageSink接口:

public abstract class AOPSink : IMessageSink???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? private SortedList m_BeforeHandles;?????????????????????????????? ????????????????????????

??????? private SortedList m_AfterHandles;?????????????????????????????? ????????????????????????

??????? private IMessageSink m_NextSink;?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

在類(lèi)AOPSink中,定義了兩個(gè)SortedList類(lèi)型的字段:m_BeforeHandles和m_AfterHandles。它們負(fù)責(zé)存放方法名與BeforeAOPHandle和AfterAOPHandle對(duì)象之間的映射。添加這些映射的職責(zé)由如下兩個(gè)方法完成:?????????????????????????? ????????????????????????

protected virtual void AddBeforeAOPHandle(string methodName, BeforeAOPHandle beforeHandle)?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

???? lock (this.m_BeforeHandles)?????????????????????????????? ????????????????????????

???? {?????????????????????????????? ????????????????????????

???????? if (!m_BeforeHandles.Contains(methodName))?????????????????????????????? ????????????????????????

? ???????{?????????????????????????????? ????????????????????????

???????????? m_BeforeHandles.Add(methodName, beforeHandle);?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

???? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

protected virtual void AddAfterAOPHandle(string methodName, AfterAOPHandle afterHandle)?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

????? lock (this.m_AfterHandles)?????????????????????????????? ????????????????????????

????? {?????????????????????????????? ????????????????????????

????????? if (!m_AfterHandles.Contains(methodName))?????????????????????????????? ????????????????????????

????????? {?????????????????????????????? ????????????????????????

????????????? m_AfterHandles.Add(methodName, afterHandle);?????????????????????????????? ????????????????????????

????????? }?????????????????????????????? ????????????????????????

????? }?????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

考慮到我們要截取的方法可能會(huì)有多個(gè),因此在類(lèi)AOPSink中,又定義了兩個(gè)抽象方法,負(fù)責(zé)添加所有的映射關(guān)系:?????????????????????????? ????????????????????????

protected abstract void AddAllBeforeAOPHandles();?????????????????????????????? ????????????????????????

protected abstract void AddAllAfterAOPHandles();?????????????????????????? ????????????????????????

?????????????????????????

然后在構(gòu)造函數(shù)中,我們初始化兩個(gè)SortedList對(duì)象,并調(diào)用上述的兩個(gè)抽象方法:?????????????????????????? ????????????????????????

??????? public AOPSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

? ??????????m_NextSink = nextSink; ????????????????????????

??????????? m_BeforeHandles = new SortedList();?????????????????????????????? ????????????????????????

??????????? m_AfterHandles = new SortedList();?????????????????????????????? ????????????????????????

??????????? AddAllBeforeAOPHandles();?????????????????????????????? ????????????????????????

??????????? AddAllAfterAOPHandles();?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

為了能夠根據(jù)方法名獲得相對(duì)應(yīng)的委托對(duì)象,我們又定義了兩個(gè)Find方法。考慮到可能會(huì)有多個(gè)用戶(hù)同時(shí)調(diào)用,在這兩個(gè)方法中,我利用lock避免了對(duì)象的爭(zhēng)用:?????????????????????????? ????????????????????????

??????? protected BeforeAOPHandle FindBeforeAOPHandle(string methodName)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? BeforeAOPHandle beforeHandle;?????????????????????????????? ????????????????????????

??????????? lock (this.m_BeforeHandles)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

??????????????? beforeHandle = (BeforeAOPHandle)m_BeforeHandles[methodName];?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? return beforeHandle;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? protected AfterAOPHandle FindAfterAOPHandle(string methodName)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? AfterAOPHandle afterHandle;?????????????????????????????? ????????????????????????

??????????? lock (this.m_AfterHandles)?????????????????????????????? ????????????????????????

???? ???????{?????????????????????????????? ????????????????????????

??????????????? afterHandle = (AfterAOPHandle)m_AfterHandles[methodName];?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? return afterHandle;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

接下來(lái)是IMessageSink接口要求實(shí)現(xiàn)的方法和屬性:?????????????????????????? ????????????????????????

??????? public IMessageSink NextSink?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? get { return m_NextSink; }?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessage SyncProcessMessage(IMessage msg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? IMethodCallMessage call = msg as IMethodCallMessage;?????????????????????????????? ????????????????????????

??????????? string methodName = call.MethodName.ToUpper();?????????????????????????????? ????????????????????????

??????????? BeforeAOPHandle beforeHandle = FindBeforeAOPHandle(methodName);?????????????????????????????? ????????????????????????

??????????? if (beforeHandle != null)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

??????????????? beforeHandle(call);?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? IMessage retMsg = m_NextSink.SyncProcessMessage(msg);?????????????????????????????? ????????????????????????

??????????? IMethodReturnMessage replyMsg = retMsg as IMethodReturnMessage;?????????????????????????????? ????????????????????????

??????????? AfterAOPHandle afterHandle = FindAfterAOPHandle(methodName);?????????????????????????????? ????????????????????????

??????????? if (afterHandle != null)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

????? ??????????afterHandle(replyMsg);?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? return retMsg;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return null;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

需要注意的是SyncProcessMessage()方法。在該方法中,通過(guò)FindBeforeAOPHandle()和FindAfterAOPHandle()方法,找到BeforeAOPHandle和AfterAOPHandle委托對(duì)象,并執(zhí)行它們。即執(zhí)行這兩個(gè)委托對(duì)象具體指向的方法,類(lèi)似與AspectJ中的before和after的execution。?????????????????????????? ????????????????????????

?????????????????????????

現(xiàn)在,我們就可以象AspectJ那樣定義自己的aspect了。如權(quán)限管理一例,我們定義一個(gè)類(lèi)AuthorizationAOPSink,它繼承了AOPSink:?????????????????????????? ????????????????????????

public class AuthorizationAOPSink : AOPSink???????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? public AuthorizationAOPSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????????? : base(nextSink)?????????????????????????????? ????????????????????????

?? {?????????????????????????????? ????????????????????????

?? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

然后在這個(gè)方法中,實(shí)現(xiàn)before和after的邏輯。注意before和after方法應(yīng)與之前定義的委托BeforeAOPHandle和AfterAOPHandle一致。不過(guò),以本例而言,并不需要實(shí)現(xiàn)after邏輯:?????????????????????????? ????????????????????????

private void Before_Authorization(IMethodCallMessage callMsg)?????????????????????????????? ????????????????????????

{?????? ?????????????????????????????? ????????????????????????

??????? if (callMsg == null)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

????????????? return;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? if (!permissions.Verify(Permission.ADMIN))?????????????????????????? ????????????????????????

?????? ?{?????????????????????????????? ????????????????????????

???????????????? throw UnauthorizedException();?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

}?????????????????????????? ????????????????????????

然后我們override基類(lèi)中的抽象方法AddAllBeforeAOPHandles()和AddAllAfterAOPHandles():?????????????????????????? ????????????????????????

protected override void AddAllBeforeAOPHandles()?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? AddBeforeAOPHandle("ADDORDER", new BeforeAOPHandle(Before_Authorization));?????????????????????????????? ????????????????????????

??????????? AddBeforeAOPHandle("DELETEORDER", new BeforeAOPHandle(Before_Authorization));?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? protected override void AddAllAfterAOPHandles()?????????????????????????????? ????????????????????????

??????? {??????????? ?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

因?yàn)閍fter邏輯不需要實(shí)現(xiàn),因此重寫(xiě)AddAllAfterAOPHandles()時(shí),使其為空就可以了(必須重寫(xiě),因?yàn)樵摲椒槌橄蠓椒?#xff09;。在AOPProperty類(lèi)中,需要返回IMessageSink對(duì)象,所以還應(yīng)修改原來(lái)的AOPProperty類(lèi)中的GetObjectSink方法:?????????????????????????? ????????????????????????

public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return new AOPSink(nextSink);???????????????????????????????? ????????????????????????

return new AuthorizationAOPSink(nextSink);??????? ?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

比較一下上述的實(shí)現(xiàn)方案,自定義的繼承AOPSink類(lèi)的AuthorizationAOPSink就相當(dāng)于AspectJ中的aspect。而與BeforeAOPHandle和AfterAOPHandle委托對(duì)應(yīng)的方法,則相當(dāng)于AspectJ的before和after語(yǔ)法。AddAllBeforeAOPHandles()和AddAllAfterAOPHandle()則相當(dāng)于AspectJ的pointcut。通過(guò)引入委托的方法,使得我們的AOP實(shí)現(xiàn),具有了AspectJ的一些特性,而這些實(shí)現(xiàn)是不需要專(zhuān)門(mén)的編譯器的。

?????????????????????????

很明顯,如果我們要求OrderManager類(lèi)中新增的UpdateOrder方法,也要加入權(quán)限控制,那么我們可以在AddAllBeforeAOPHandles()方法中,增加UpdaeOrder方法與before邏輯的映射:

AddBeforeAOPHandle("UPDATEORDER", Before_Authorization);?????????????????????????????? ????????????????????????

同樣的,如果要對(duì)權(quán)限控制進(jìn)行修改,開(kāi)發(fā)業(yè)務(wù)經(jīng)理對(duì)訂單管理的權(quán)限,那么也只需要修改Before_Authorization()方法:

private void Before_Authorization(IMessage callMsg)?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

?????? IMethodCallMessage call = callMsg as IMethodCallMessage;?????????????????????????????? ????????????????????????

??????? if (call == null)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

????????????? return;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? if (!(permissions.Verify(Permission.ADMIN)|| permissions.Verify(Permission.MANAGER)))?????????????????????????? ????????????????????????

?????? ?{?????????????????????????????? ????????????????????????

???????????????? throw UnauthorizedException();?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

?????????????????????????

四、進(jìn)一步完善?????????????????????????? ????????????????????????

由于我們的委托列表m_BeforeHandles和m_AfterHandles為SortedList類(lèi)型,因此作為key的methodName必須是唯一的。如果系統(tǒng)要求添加其他權(quán)限控制的邏輯,例如增加認(rèn)證功能,就不能再在AuthorizationAOPSink類(lèi)的AddAllBeforeAOPHandles()方法中增加方法名與認(rèn)證功能的before邏輯之間的映射了。?????????????????????????? ????????????????????????

private void Before_Authentication(IMessage callMsg){……}?????????????????????????????? ????????????????????????

protected override void AddAllBeforeAOPHandles()?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

?????? ……?????????????????????????????? ????????????????????????

?????? AddBeforeAOPHandle("ADDORDER", new BeforeAOPHandle(Before_ Authentication));?????????????????????????????? ????????????????????????

?????? AddBeforeAOPHandle("DELETEORDER", new BeforeAOPHandle(Before_ Authentication));?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

如果在AuthorizationAOPSink類(lèi)中添加上面的代碼,由于新增的“ADDORDER”key與前面重復(fù),故執(zhí)行程序時(shí),是找不到相應(yīng)的委托Before_Authentication的。?????????????????????????? ????????????????????????

?????????????????????????

解決的辦法就是為認(rèn)證功能新定義一個(gè)aspect。由于在本方案中,實(shí)現(xiàn)AOP功能的不僅僅是實(shí)現(xiàn)了IMessageSink接口的AOPSink類(lèi),同時(shí)該類(lèi)還與Property、Attribute有關(guān)。也就是說(shuō),如果我們新定義一個(gè)AuthenticationAOPSink,那么還要定義與之對(duì)應(yīng)的AuthenticationAOPProperty類(lèi)。為便于擴(kuò)展,我采用了Template Method模式,為所有的property定義了抽象類(lèi)AOPProperty,其中的抽象方法或虛方法,則留待其子類(lèi)來(lái)實(shí)現(xiàn)。?????????????????????????? ????????????????????????

??? public abstract class AOPProperty : IContextProperty, IContributeObjectSink???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? protected abstract IMessageSink CreateSink(IMessageSink nextSink);?????????????????????????????? ????????????????????????

??????? protected virtual string GetName()?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return "AOP";?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? protected virtual void FreezeImpl(Context newContext)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? protected virtual bool CheckNewContext(Context newCtx)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return true;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #region IContributeObjectSink Members?????????????????????????????? ????????????????????????

??????? public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return CreateSink(nextSink);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

?????????????????????????

??????? #region IContextProperty Members?????????????????????????????? ????????????????????????

??????? public void Freeze(Context newContext)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? FreezeImpl(newContext);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? public bool IsNewContextOK(Context newCtx)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return CheckNewContext(newCtx);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? public string Name?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? get { return GetName(); }?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

與原來(lái)的AOPProperty類(lèi)相比,IContextProperty,IContributeObjectSink接口的方法與屬性,都沒(méi)有直接實(shí)現(xiàn),而是在其內(nèi)部調(diào)用了相關(guān)的抽象方法和虛方法。包括:抽象方法CreateSink(),虛方法FreezeImpl(),CheckNewContext()以及GetName()。對(duì)于其子類(lèi)而言,需要override的,主要是抽象方法CreateSink()和GetName()(因?yàn)镻roperty的Name必須是唯一的),至于其他虛方法,可以根據(jù)需要選擇是否override。例如,自定義權(quán)限控制的屬性類(lèi)AuthorizationAOPProperty:?????????????????????????? ????????????????????????

??? public class AuthorizationAOPProperty :AOPProperty???????????????????????????????? ????????????????????????

??? {??? ?????????????????????????????? ????????????????????????

??????? protected override IMessageSink CreateSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return new AuthorizationAOPSink(nextSink);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? protected override string GetName()?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return "AuthorizationAOP";?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????? ????????????????????????

在該類(lèi)中,我們override了CreateSink()方法,創(chuàng)建了一個(gè)AuthorizationAOPSink對(duì)象。同時(shí)override了虛方法GetName,返回了自己的一個(gè)名字“AuthorizationAOP”。?????????????????????????? ????????????????????????

?????????????????????????

關(guān)于Attribute類(lèi),觀察其方法GetPropertiesForNewContext(),其實(shí)現(xiàn)是在IConstructionCallMessage消息的上下文property中添加自定義property。這些property組成了一個(gè)鏈,它是可以靜態(tài)添加的。鑒于此,我們可以采取兩種策略:?????????????????????????? ????????????????????????

1、 所有的aspect都使用同一個(gè)Attribute。其實(shí)現(xiàn)如下:?????????????????????????? ????????????????????????

??? [AttributeUsage(AttributeTargets.Class)]?????????????????????????????? ????????????????????????

??? public class AOPAttribute:ContextAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? public AOPAttribute()?????????????????????????????? ????????????????????????

??????????? : base("AOP")?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

? ??????????ctorMsg.ContextProperties.Add(new AuthorizationAOPProperty());?????????????????????????????? ????????????????????????

??????????? ctorMsg.ContextProperties.Add(new AuthenticationAOPProperty());?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

在方法GetPropertiesForNewContext()中,添加多個(gè)自定義Property。在添加Property時(shí),需要注意添加Property的順序。?????????????????????????? ????????????????????????

2、 不同的aspect使用不同的Attribute。此時(shí)可以為這些Attribute定義一個(gè)共同的抽象基類(lèi)AOPAttribute:?????????????????????????? ????????????????????????

[AttributeUsage(AttributeTargets.Class)]?????????????????????????????? ????????????????????????

??? public abstract class AOPAttribute:ContextAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? public AOPAttribute()?????????????????????????????? ????????????????????????

???????????? : base("AOP")?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? public sealed override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? ctorMsg.ContextProperties.Add(GetAOPProperty());?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected abstract AOPProperty GetAOPProperty();???????? ?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

注:我將GetPropertiesForNewContext()方法sealed,目的是不需要其子類(lèi)在重寫(xiě)該方法。?????????????????????????? ????????????????????????

?????????????????????????

繼承AOPAttribute類(lèi)的子類(lèi)只需要重寫(xiě)GetAOPProperty()方法即可。但在為OrderManager類(lèi)定義Attribute的時(shí)候,需注意其順序。如以下的順序:?????????????????????????? ????????????????????????

[AuthorizationAOP]?????????????????????????????? ????????????????????????

[AuthenticationAOP]?????????????????????????????? ????????????????????????

public class OrderManager{}?????????????????????????????? ????????????????????????

此時(shí),AuthorizationAOPAttribute在前,AuthenticationAOPAttribute在后。如果以Decorator的角度來(lái)看,對(duì)被裝飾的方法,AuthorizationAOPAttribute在內(nèi),AuthenticationAOPAttribute在外。?????????????????????????? ????????????????????????

考慮到aspect的應(yīng)用,有的方法需要多個(gè)aspect,有的則只需要單個(gè)aspect,所以,第二個(gè)方案更佳。?????????????????????????? ????????????????????????

?????????????????????????

五、AOP實(shí)例?????????????????????????? ????????????????????????

接下來(lái),我通過(guò)一個(gè)實(shí)例,介紹AOP的具體實(shí)現(xiàn)。假定我們要設(shè)計(jì)一個(gè)計(jì)算器,它能提供加法和減法功能。我們希望,在計(jì)算過(guò)程中,能夠通過(guò)日志記錄整個(gè)計(jì)算過(guò)程及其結(jié)果,同時(shí)需要監(jiān)測(cè)其運(yùn)算性能。該例中,核心業(yè)務(wù)是加法和減法,而公共的業(yè)務(wù)則是日志與監(jiān)測(cè)功能。根據(jù)前面對(duì)AOP的分析,這兩個(gè)功能應(yīng)為我們整個(gè)系統(tǒng)需要?jiǎng)冸x出來(lái)的“方面”。?????????????????????????? ????????????????????????

?????????????????????????

我們已經(jīng)擁有了一個(gè)AOP實(shí)現(xiàn)機(jī)制,以及核心的類(lèi)庫(kù),包括AOPSink、AOPProperty、AOPAttribute三個(gè)抽象基類(lèi)。現(xiàn)在,我們分別為日志aspect和監(jiān)測(cè)aspect,定義相應(yīng)的Sink、Property、Attribute。?????????????????????????? ????????????????????????

?????????????????????????

首先是日志aspect:?????????????????????????? ????????????????????????

LogAOPSink.cs:?????????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Messaging;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for LogAOPSink.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? public class LogAOPSink:AOPSink???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? public LogAOPSink(IMessageSink nextSink):base(nextSink)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? ?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override void AddAllBeforeAOPHandles()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

?????????? ???AddBeforeAOPHandle("ADD",new BeforeAOPHandle(Before_Log));?????????????????????????????? ????????????????????????

???????????? AddBeforeAOPHandle("SUBSTRACT",new BeforeAOPHandle(Before_Log));?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override void AddAllAfterAOPHandles()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? AddAfterAOPHandle("ADD",new AfterAOPHandle(After_Log));?????????????????????????????? ????????????????????????

???????????? AddAfterAOPHandle("SUBSTRACT",new AfterAOPHandle(After_Log));?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? private void Before_Log(IMethodCallMessage callMsg)?????????????????????????????? ????????????????????????

???????? {??????????? ?????????????????????????????? ????????????????????????

???????????? if (callMsg == null)?????????????????????????????? ????????????????????????

???????????? {?????????????????????????????? ????????????????????????

????????????????? return;?????????????????????????????? ????????????????????????

???????????? }??????????? ?????????????????????????????? ????????????????????????

????????????????????? ?Console.WriteLine("{0}({1},{2})",callMsg.MethodName,callMsg.GetArg(0),callMsg.GetArg(1));?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? private void After_Log(IMethodReturnMessage replyMsg)?????????????????????????????? ????????????????????????

???????? {??????????? ?????????????????????????????? ????????????????????????

???????????? if (replyMsg == null)?????????????????????????????? ????????????????????????

???????????? {?????????????????????????????? ????????????????????????

????????????????? return;?????????????????????????????? ????????????????????????

???????????? }??????????? ?????????????????????????????? ????????????????????????

???????????? Console.WriteLine("Result is {0}",replyMsg.ReturnValue);????????? ?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

?????????????????????????

LogAOPProperty.cs?????????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Messaging;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for LogAOPProperty.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? public class LogAOPProperty:AOPProperty???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? protected override IMessageSink CreateSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return new LogAOPSink(nextSink);?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override string GetName()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return "LogAOP";?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

LogAOPAttribute.cs:?????????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Activation;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Contexts;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for LogAOPAttribute.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? [AttributeUsage(AttributeTargets.Class)]?????????????????????????????? ????????????????????????

??? public class LogAOPAttribute:AOPAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? protected override AOPProperty GetAOPProperty()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return new LogAOPProperty();?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? ?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

?????????????????????????

然后再定義監(jiān)測(cè)aspect:?????????????????????????? ????????????????????????

MonitorAOPSink.cs:?????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Messaging;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for MonitorAOPSink.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? public class MonitorAOPSink:AOPSink???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? public MonitorAOPSink(IMessageSink nextSink):base(nextSink)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? ?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override void AddAllBeforeAOPHandles()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? AddBeforeAOPHandle("ADD",new BeforeAOPHandle(Before_Monitor));?????????????????????????????? ????????????????????????

???????????? AddBeforeAOPHandle("SUBSTRACT",new BeforeAOPHandle(Before_Monitor));?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

???????? protected override void AddAllAfterAOPHandles()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? AddAfterAOPHandle("ADD",new AfterAOPHandle(After_Monitor));?????????????????????????????? ????????????????????????

???????????? AddAfterAOPHandle("SUBSTRACT",new AfterAOPHandle(After_Monitor));?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? private void Before_Monitor(IMethodCallMessage callMsg)?????????????????????????????? ????????????????????????

???????? {??????????? ?????????????????????????????? ????????????????????????

???????????? if (callMsg == null)?????????????????????????????? ????????????????????????

???????????? {?????????????????????????????? ????????????????????????

????????????????? return;?????????????????????????????? ????????????????????????

???????????? }?????????????????????????????? ????????????????????????

???????????? Console.WriteLine("Before {0} at {1}",callMsg.MethodName,DateTime.Now);?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

???????? private void After_Monitor(IMethodReturnMessage replyMsg)?????????????????????????????? ????????????????????????

???????? {??????????? ?????????????????????????????? ????????????????????????

???????????? if (replyMsg == null)?????????????????????????????? ????????????????????????

???????????? {?????????????????????????????? ????????????????????????

????????????????? return;?????????????????????????????? ????????????????????????

???????????? }?????????????????????????????? ????????????????????????

???????????? Console.WriteLine("After {0} at {1}",replyMsg.MethodName,DateTime.Now);?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

MonitorAOPProperty.cs:?????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Messaging;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for MonitorAOPProperty.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? public class MonitorAOPProperty:AOPProperty???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? public MonitorAOPProperty()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? //???????????????????????????????? ????????????????????????

???????????? // TODO: Add constructor logic here???????????????????????????????? ????????????????????????

???????????? //???????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override IMessageSink CreateSink(IMessageSink nextSink)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return new MonitorAOPSink(nextSink);?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? protected override string GetName()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return "MonitorAOP";?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

MonitorAOPAttribute.cs:?????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Activation;?????????????????????????????? ????????????????????????

using System.Runtime.Remoting.Contexts;?????????????????????????????? ????????????????????????

using Wayfarer.AOP;?????????????????????????????? ????????????????????????

?????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for MonitorAOPAttribute.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? [AttributeUsage(AttributeTargets.Class)]?????????????????????????????? ????????????????????????

??? public class MonitorAOPAttribute:AOPAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? protected override AOPProperty GetAOPProperty()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return new MonitorAOPProperty();?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

注意在這兩個(gè)方面中,各自的Property的Name必須是唯一的。?????????????????????????? ????????????????????????

現(xiàn)在,可以定義計(jì)算器類(lèi)。?????????????????????????? ????????????????????????

Calculator.cs:?????????????????????????? ????????????????????????

using System;

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for Calculator.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? [MonitorAOP]?????????????????????????????? ????????????????????????

??? [LogAOP]?????????????????????????????? ????????????????????????

??? public class Calculator:ContextBoundObject???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? public int Add(int x,int y)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return x + y;?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

?????????????????????????

???????? public int Substract(int x,int y)?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? return x - y;?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

需要注意的是Calculator類(lèi)必須繼承ContextBoundObject類(lèi)。?????????????????????????? ????????????????????????

最后,我們寫(xiě)一個(gè)控制臺(tái)程序來(lái)執(zhí)行Calculator:?????????????????????????? ????????????????????????

Program.cs:?????????????????????????????? ????????????????????????

using System;?????????????????????????????? ????????????????????????

namespace Wayfarer.AOPSample?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? /// <summary>???????????????????????????????? ????????????????????????

??? /// Summary description for Class1.???????????????????????????????? ????????????????????????

??? /// </summary>???????????????????????????????? ????????????????????????

??? class Program???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

???????? /// <summary>???????????????????????????????? ????????????????????????

???????? /// The main entry point for the application.???????????????????????????????? ????????????????????????

???????? /// </summary>???????????????????????????????? ????????????????????????

???????? [STAThread]?????????????????????????????? ????????????????????????

???????? static void ?????????????????????????? Main?????????????????????????? (string[] args)???????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? Calculator cal = new Calculator();?????????????????????????????? ????????????????????????

???????????? cal.Add(3,5);?????????????????????????????? ????????????????????????

???????????? cal.Substract(3,5);?????????????????????????????? ????????????????????????

???????????? Console.ReadLine();?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

運(yùn)行結(jié)果如下:?????????????????????????? ????????????????????????

?

六、結(jié)論?????????????????????????? ????????????????????????

在.Net平臺(tái)下采用動(dòng)態(tài)代理技術(shù)實(shí)現(xiàn)AOP,其原理并不復(fù)雜,而.Net Framework也提供了足夠的技術(shù)來(lái)實(shí)現(xiàn)它。如果再結(jié)合好的設(shè)計(jì)模式,提供一個(gè)基本的AOP框架,將大大地簡(jiǎn)化開(kāi)發(fā)人員處理“aspect”的工作。當(dāng)然,本文雖然提供了實(shí)現(xiàn)AOP的實(shí)例,但其架構(gòu)的設(shè)計(jì)還遠(yuǎn)遠(yuǎn)不能達(dá)到企業(yè)級(jí)的要求,如在穩(wěn)定性、可擴(kuò)展性上還需經(jīng)過(guò)進(jìn)一步的測(cè)試與改善。例如我們可以通過(guò)配置文件的形式,來(lái)配置方法與方面之間的映射。同時(shí),由于采用了動(dòng)態(tài)代理,在性能上還期待改進(jìn)。?????????????????????????? ????????????????????????

?????????????????????????

使用動(dòng)態(tài)代理技術(shù)實(shí)現(xiàn)AOP,對(duì)實(shí)現(xiàn)AOP的類(lèi)有一個(gè)限制,就是必須派生于ContextBoundObject類(lèi),這對(duì)于單繼承語(yǔ)言來(lái)說(shuō),確實(shí)是一個(gè)比較致命的缺陷。所謂“仁者見(jiàn)仁,智者見(jiàn)智”,這就需要根據(jù)項(xiàng)目的情況,做出正確的抉擇了。?????????????????????????? ????????????????????????

?????????????????????????

參考:?????????????????????????? ????????????????????????

1、 JGTM,《A Taste of AOP from Solving Problems with OOP and Design Patterns》?????????????????????????? ????????????????????????

2、 NiWalker,《Attribute在.Net編程的應(yīng)用》?????????????????????????? ????????????????????????

3、板橋里人,《AOP與權(quán)限控制實(shí)現(xiàn)》????????????????????????

在《在.Net中關(guān)于AOP的實(shí)現(xiàn)》我通過(guò)動(dòng)態(tài)代理的技術(shù),基本上實(shí)現(xiàn)了AOP的幾個(gè)技術(shù)要素,包括aspect,advice,pointcut。在文末我提到采用配置文件方式,來(lái)獲取advice和pointcut之間的映射,從而使得構(gòu)建aspect具有擴(kuò)展性。

細(xì)細(xì)思考這個(gè)問(wèn)題,我發(fā)現(xiàn)使用delegate來(lái)構(gòu)建advice,似乎并非一個(gè)明智的選擇。我在建立映射關(guān)系時(shí),是將要攔截的方法名和攔截需要實(shí)現(xiàn)的aspect邏輯建立一個(gè)對(duì)應(yīng)關(guān)系,而該aspect邏輯確實(shí)可以通過(guò)delegate,使其指向一族方法簽名與該委托完全匹配的方法。這使得advice能夠抽象化,以便于具體實(shí)現(xiàn)的擴(kuò)展。然而,委托其實(shí)現(xiàn)畢竟是面向過(guò)程的范疇,雖然在.Net下,delegate本身仍是一個(gè)類(lèi)對(duì)象,然而在創(chuàng)建具體的委托實(shí)例時(shí),仍然很難通過(guò)配置文件和反射技術(shù)來(lái)獲得。

?????????????????????????

考慮到委托具有的接口抽象的本質(zhì),也許采用接口的方式來(lái)取代委托更為可行。在之前的實(shí)現(xiàn)方案中,我為advice定義了兩個(gè)委托:

public delegate void BeforeAOPHandle(IMethodCallMessage callMsg);?????????????????????????????? ????????????????????????

public delegate void AfterAOPHandle(IMethodReturnMessage replyMsg);?????????????????????????????? ????????????????????????

?????????????????????????

我可以定義兩個(gè)接口IBeforeAction和IAfterAction,分別與這兩個(gè)委托相對(duì)應(yīng):???????????????????????????????? ????????????????????????

??? public interface IBeforeAdvice???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? void BeforeAdvice(IMethodCallMessage callMsg);?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

??? public interface IAfterAdvice???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? void AfterAdvice(IMethodReturnMessage returnMsg);?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

通過(guò)定義的接口,可以將Advice與Aspect分離開(kāi)來(lái),這也完全符合OO思想中的“責(zé)任分離”原則。?????????????????????????? ????????????????????????

(注:為什么要為Advice定義兩個(gè)接口?這是考慮到有些Aspect只需要提供Before或After兩個(gè)邏輯之一,如權(quán)限控制,就只需要before Action。)?????????????????????????? ????????????????????????

?????????????????????????

那么當(dāng)類(lèi)庫(kù)使用者,要定義自己的Aspect時(shí),就可以定義具體的Advice類(lèi),來(lái)實(shí)現(xiàn)這兩個(gè)接口,以及具體的Advice邏輯了。例如,之前提到的日志Aspect:?????????????????????????? ????????????????????????

??? public class LogAdvice:IAfterAdvice,IBeforeAdvice???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? #region IBeforeAdvice Members?????????????????????????????? ????????????????????????

?????????????????????????

??????? public void BeforeAdvice(IMethodCallMessage callMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? if (callMsg == null)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

?????????? ?????return;?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? Console.WriteLine("{0}({1},{2})", callMsg.MethodName, callMsg.GetArg(0), callMsg.GetArg(1));?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

?????????????????????????

??????? #region IAfterAdvice Members?????????????????????????????? ????????????????????????

?????????????????????????

??????? public void AfterAdvice(IMethodReturnMessage returnMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? if (returnMsg == null)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

??????????????? return;?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? Console.WriteLine("Result is {0}", returnMsg.ReturnValue);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

?????????????????????????

而在AOPSink類(lèi)的派生類(lèi)中,添加方法名與Advice映射關(guān)系(此映射關(guān)系,我們即可理解為AOP的pointcut)時(shí),就可以添加實(shí)現(xiàn)了Advice接口的類(lèi)對(duì)象,如:?????????????????????????? ????????????????????????

???????? public override void AddAllBeforeAdvices()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

??????????? AddBeforeAdvice("ADD",new LogAdvice());?????????????????????????????? ????????????????????????

??????????? AddBeforeAdvice("SUBSTRACT", new LogAdvice());?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

???????? public override void AddAllAfterAdvices()?????????????????????????????? ????????????????????????

???????? {?????????????????????????????? ????????????????????????

???????????? AddAfterAdvice("ADD",new LogAdvice());?????????????????????????????? ????????????????????????

??????????? AddAfterAdvice("SUBSTRACT", new LogAdvice());?????????????????????????????? ????????????????????????

???????? }?????????????????????????????? ????????????????????????

由于LogAdvice類(lèi)實(shí)現(xiàn)了接口IBeforeAdvice和IAfterAdvice,因此諸如new LogAdvice的操作均可以通過(guò)反射來(lái)創(chuàng)建該實(shí)例,如:?????????????????????????? ????????????????????????

IBeforeAdvice beforeAdvice =?????????????????????????? ????????????????????????

(IBeforeAdvice)Activator.CreateInstance("Wayfarer.AOPSample","Wayfarer.AOPSample.LogAdvice").Unwrap();?????????????????????????????? ????????????????????????

而CreateInstance()方法的參數(shù)值,是完全可以通過(guò)配置文件來(lái)配置的:?????????????????????????? ????????????????????????

<aop>????????????????????????????? ????????????????????????

??? <aspect value ="LOG">??????????????????????????????? ????????????????????????

???????? <advice type="before" assembly="Wayfarer.AOPSample" class="Wayfarer.AOPSample.LogAdvice">??????????????????????????????? ????????????????????????

???????????? <pointcut>ADD</pointcut>??????????????????????????????? ????????????????????????

???????????? <pointcut>SUBSTRACT</pointcut>??????????????????????????????? ????????????????????????

???????? </advice>????????????????????????????? ????????????????????????

???????? <advice type="after" assembly="Wayfarer.AOPSample" class="Wayfarer.AOPSample.LogAdvice">??????????????????????????????? ????????????????????????

???????????? <pointcut>ADD</pointcut>??????????????????????????????? ????????????????????????

???????????? <pointcut>SUBSTRACT</pointcut>??????????????????????????????? ????????????????????????

???????? </advice>????????????????????????????? ????????????????????????

??? </aspect>??? ?????????????????????????????? ????????????????????????

</aop>?????????????????????????? ????????????????????????

這無(wú)疑改善了AOP實(shí)現(xiàn)的擴(kuò)展性。?????????????????????????? ????????????????????????

?????????????????????????

《在.Net中關(guān)于AOP的實(shí)現(xiàn)》實(shí)現(xiàn)AOP的方案,要求包含被攔截方法的類(lèi)必須繼承ContextBoundObject。這是一個(gè)比較大的限制。不僅如此,ContextBoundObject對(duì)程序的性能也有極大的影響。我們可以做一個(gè)小測(cè)試。定義兩個(gè)類(lèi),其中一個(gè)類(lèi)繼承ContextBoundObject。它們都實(shí)現(xiàn)了一個(gè)累加的操作:

class NormalObject???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? public void Sum(int n)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

?????? ?????int sum = 0;?????????????????????????????? ????????????????????????

??????????? for (int i = 1; i <= n; i++)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

??????????????? sum += i;?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? Console.WriteLine("The result is {0}",sum);?????????????????????????????? ????????????????????????

??????????? Thread.Sleep(10);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

?????????????????????????

??? class MarshalObject:ContextBoundObject???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? public void Sum(int n)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? int sum = 0;?????????????????????????????? ????????????????????????

??????????? for (int i = 1; i <= n; i++)?????????????????????????????? ????????????????????????

??????????? {?????????????????????????????? ????????????????????????

??????????????? sum += i;?????????????????????????????? ????????????????????????

??????????? }?????????????????????????????? ????????????????????????

??????????? Console.WriteLine("The result is {0}", sum);?????????????????????????????? ????????????????????????

??????????? Thread.Sleep(10);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }?????????????????????????????? ????????????????????????

然后執(zhí)行這兩個(gè)類(lèi)的Sum()方法,測(cè)試其性能:

??? class Program???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? static void ?????????????????????????? Main?????????????????????????? (string[] args)???????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? long normalObjMs, marshalObjMs;?????????????????????????????? ????????????????????????

??????????? Stopwatch watch = new Stopwatch();?????????????????????????????? ????????????????????????

??????????? NormalObject no = new NormalObject();?????????????????????????????? ????????????????????????

??????????? MarshalObject mo = new MarshalObject();?????????????????????????????? ????????????????????????

?????????????????????????

??????????? watch.Start();?????????????????????????????? ????????????????????????

??????????? no.Sum(1000000);?????????????????????????????? ????????????????????????

??????????? watch.Stop();?????????????????????????????? ????????????????????????

??????????? normalObjMs = watch.ElapsedMilliseconds;?????????????????????????????? ????????????????????????

??????????? watch.Reset();?????????????????????????????? ????????????????????????

?????????????????????????

??????????? watch.Start();?????????????????????????????? ????????????????????????

??????????? mo.Sum(1000000);?????????????????????????????? ????????????????????????

??????????? watch.Stop();?????????????????????????????? ????????????????????????

??????????? marshalObjMs = watch.ElapsedMilliseconds;?????????????????????????????? ????????????????????????

??????????? watch.Reset();?????????????????????????????? ????????????????????????

?????????????????????????

??????????? Console.WriteLine("The normal object consume {0} milliseconds.",normalObjMs);?????????????????????????????? ????????????????????????

??????????? Console.WriteLine("The contextbound object consume {0} milliseconds.",marshalObjMs);??????????? ?????????????????????????????? ????????????????????????

??????????? Console.ReadLine();?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??? }

得到的結(jié)果如下:

?

從性能的差異看,兩者之間的差距是比較大的。如果將其應(yīng)用在企業(yè)級(jí)的復(fù)雜邏輯上,這種區(qū)別就非常明顯了,對(duì)系統(tǒng)帶來(lái)的影響也是非常巨大的。

?????????????????????????

另外,在《在.Net中關(guān)于AOP的實(shí)現(xiàn)》文章后,有朋友發(fā)表了很多中肯的意見(jiàn)。其中有人提到了AOPAttribute繼承ContextAttribute的問(wèn)題。評(píng)論中提及微軟在以后的版本中,不再提供ContextAttribute。如果真是如此,確有必要放棄繼承ContextAttribute的形式。不過(guò),在.Net中,除了ContextAttribute之外,還提供有一個(gè)接口IContextAttribute,該接口的定義為:

public interface IContextAttribute?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??????? void GetPropertiesForNewContext(IConstructionCallMessage msg);?????????????????????????????? ????????????????????????

??????? bool IsContextOK(Context ctx, IConstructionCallMessage msg);???????

}?????????????????????????????? ????????????????????????

此時(shí)只需要將原來(lái)的AOPAttribute實(shí)現(xiàn)該接口即可:???????????????????????????????? ????????????????????????

??? public abstract class AOPAttribute:Attribute,IContextAttribute//ContextAttribute???????????????????????????????? ????????????????????????

??? {?????????????????????????????? ????????????????????????

??????? #region IContextAttribute Members?????????????????????????????? ????????????????????????

??????? public void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? AOPProperty property = GetAOPProperty();?????????????????????????????? ????????????????????????

??????????? property.AspectXml = m_AspectXml;?????????????????????????????? ????????????????????????

??????????? property.AspectXmlFlag = m_AspectXmlFlag;?????????????????????????????? ????????????????????????

??????????? ctorMsg.ContextProperties.Add(property);?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

?????????????????????????

??????? public bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)?????????????????????????????? ????????????????????????

??????? {?????????????????????????????? ????????????????????????

??????????? return false;?????????????????????????????? ????????????????????????

??????? }?????????????????????????????? ????????????????????????

??????? #endregion?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

不知道,IContextAttribute似乎也會(huì)在未來(lái)的版本中被取消呢??????????????????????????? ????????????????????????

?????????????????????????

然而,從總體來(lái)看,這種使用ContextBoundObject的方式是不太理想的,也許它只能停留在實(shí)驗(yàn)室階段,或許期待微軟在未來(lái)的版本中得到更好的解決!??????????????????????????? ????????????????????????

?????????????????????????

當(dāng)然,如果采用Castle的DynamicProxy技術(shù),可以突破必須繼承CotextBoundObject的局限,但隨著而來(lái)的局限卻是AOP攔截的方法,要求必須是virtual的。坦白說(shuō),這樣的限制,不過(guò)與前者乃“五十步笑百步”的區(qū)別而已。我還是期待有更好的解決方案。?????????????????????????? ????????????????????????

?????????????????????????

說(shuō)到AOP的幾大要素,在這里可以補(bǔ)充說(shuō)說(shuō),它主要包括:?????????????????????????? ????????????????????????

1、Cross-cutting concern

?????????????????????????

  在OO模型中,雖然大部份的類(lèi)只有單一的、特定的功能,但它們通常會(huì)與其他類(lèi)有著共同的第二需求。例如,當(dāng)線(xiàn)程進(jìn)入或離開(kāi)某個(gè)方法時(shí),我們可能既要在數(shù)據(jù)訪問(wèn)層的類(lèi)中記錄日志,又要在UI層的類(lèi)中記錄日志。雖然每個(gè)類(lèi)的基本功能極然不同,但用來(lái)滿(mǎn)足第二需求的代碼卻基本相同。

?????????????????????????

2、Advice

?????????????????????????

  它是指想要應(yīng)用到現(xiàn)有模型的附加代碼。例如在《在.Net中關(guān)于AOP的實(shí)現(xiàn)》的例子中,是指關(guān)于打印日志的邏輯代碼。

?????????????????????????

3、Point-cut

?????????????????????????

  這個(gè)術(shù)語(yǔ)是指應(yīng)用程序中的一個(gè)執(zhí)行點(diǎn),在這個(gè)執(zhí)行點(diǎn)上需要采用前面的cross-cutting concern。如例子中,執(zhí)行Add()方法時(shí)出現(xiàn)一個(gè)Point-cut,當(dāng)方法執(zhí)行完畢,離開(kāi)方法時(shí)又出現(xiàn)另一個(gè)Point-cut。

?????????????????????????

4、Aspect

?????????????????????????

Point-cut和advice結(jié)合在一起就叫做aspect。如例子中的Log和Monitor。在對(duì)本例的重構(gòu)中,我已經(jīng)AOPSink更名為Aspect,相應(yīng)的LogAOPSink、MonitorAOPSink也更名為L(zhǎng)ogAspect,MonitorAspect。

?????????????????????????

以上提到的PointCut和Advice在AOP技術(shù)中,通常稱(chēng)為動(dòng)態(tài)橫切技術(shù)。與之相對(duì)應(yīng)的,是較少被提及的靜態(tài)橫切。它與動(dòng)態(tài)橫切的區(qū)別在于它并不修改一個(gè)給定對(duì)象的執(zhí)行行為,相反,它允許通過(guò)引入附加的方法屬性和字段來(lái)修改對(duì)象固有的結(jié)構(gòu)。在很多AOP實(shí)現(xiàn)中,將靜態(tài)橫切稱(chēng)為introduce或者mixin。?????????????????????????? ????????????????????????

?????????????????????????

在開(kāi)發(fā)應(yīng)用系統(tǒng)時(shí),如果需要在不修改原有代碼的前提下,引入第三方產(chǎn)品和API庫(kù),靜態(tài)橫切技術(shù)是有很大的用武之地的。從這一點(diǎn)來(lái)看,它有點(diǎn)類(lèi)似于設(shè)計(jì)模式中提到的Adapter模式需要達(dá)到的目標(biāo)。不過(guò),看起來(lái)靜態(tài)橫切技術(shù)應(yīng)比Adapter模式更加靈活和功能強(qiáng)大。?????????????????????????? ????????????????????????

?????????????????????????

例如,一個(gè)已經(jīng)實(shí)現(xiàn)了收發(fā)郵件的類(lèi)Mail。然而它并沒(méi)有實(shí)現(xiàn)地址驗(yàn)證的功能。現(xiàn)在第三方提供了驗(yàn)證功能的接口IValidatable:?????????????????????????? ????????????????????????

public interface IValidatable?????????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

??? bool ValidateAddress();?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

如果沒(méi)有AOP,采用設(shè)計(jì)模式的方式,在不改變Mail類(lèi)的前提下,可以通過(guò)Adapter模式,引入MailAdater,繼承Mail類(lèi),同時(shí)實(shí)現(xiàn)IValidatable接口。采用introduce技術(shù),卻更容易實(shí)現(xiàn)該功能的擴(kuò)展,我們只需要定義aspect:(注:java代碼,使用了AspectJ)?????????????????????????? ????????????????????????

import com.acme.validate.Validatable;?????????????????????????????? ????????????????????????

?????????????????????????

public aspect EmailValidateAspect?????????????????????????? ????????????????????????

{?????????????????????????????? ????????????????????????

?? declare parents: Email implements IValidatable;?????????????????????????????? ????????????????????????

?????????????????????????

?? public boolean Email.validateAddress(){?????????????????????????????? ????????????????????????

???? if(this.getToAddress() != null){?????????????????????????????? ????????????????????????

?????? ?? return true;?????????????????????????????? ????????????????????????

???? }else{?????????????????????????????? ????????????????????????

?????? ?? return false;?????????????????????????????? ????????????????????????

???? }?????????????????????????????? ????????????????????????

?? }?????????????????????????????? ????????????????????????

}?????????????????????????????? ????????????????????????

?????????????????????????

從上可以看到,通過(guò)EmailValidateAspect方面,為Email類(lèi)introduce了新的方法ValidateAddress()。非常容易的就完成了Email的擴(kuò)展。?????????????????????????? ????????????????????????

?????????????????????????

我們可以比較一下,如果采用Adapter模式,原有的Email類(lèi)是不能被顯示轉(zhuǎn)換為IValidatable接口的,也即是說(shuō)如下的代碼是不可行的:?????????????????????????? ????????????????????????

Email mail = new Email();?????????????????????????????? ????????????????????????

IValidatable validate = ((IValidatable)mail).ValidateAddress();?????????????????????????????? ????????????????????????

要調(diào)用ValidateAddress()方法,必須通過(guò)EmailAdapter類(lèi)。然而通過(guò)靜態(tài)橫切技術(shù),上面的代碼就完全可行了。?????????????????????????? ????????????????????????

?????????????????????????

靜態(tài)橫切的技術(shù)在企業(yè)應(yīng)用上還需要進(jìn)一步驗(yàn)證和測(cè)試,不過(guò)遺憾的是,《在.Net中關(guān)于AOP的實(shí)現(xiàn)》一文采用的動(dòng)態(tài)代理技術(shù),是無(wú)法完成實(shí)現(xiàn)靜態(tài)橫切的目標(biāo)的。

轉(zhuǎn)載于:https://www.cnblogs.com/wangwangfei/p/4387643.html

總結(jié)

以上是生活随笔為你收集整理的【转】在.Net中关于AOP的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。