.NET AOP的實現

1、AOP實現初步java

AOP將軟件系統分爲兩個部分:核心關注點和橫切關注點。核心關注點更多的是Domain Logic,關注的是系統核心的業務;而橫切關注點雖與核心的業務實現無關,但它倒是一種更Common的業務,各個關注點離散地分佈於核心業務的多處。這意味着,若是不該用AOP,那麼這些橫切關注點所表明的業務代碼,就會分散在系統各處,致使系統中的每一個模塊都與這些業務具備很強的依賴性。在這裏,所謂橫切關注點所表明的業務,即爲「方面(Aspect)」,常見的包括權限控制、日誌管理、事務處理等等。 程序員

以權限控制爲例,假設一個電子商務系統,須要對訂單管理用戶進行權限斷定,只有系統用戶才能添加、修改和刪除訂單,那麼傳統的設計方法是:設計模式

public class OrderManager架構

{app

private ArrayList m_Orders;框架

public OrderManager()異步

{ide

       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);

    }

}

}

這樣的設計其缺陷是將訂單管理業務與權限管理徹底結合在一塊兒,耦合度高。而在一個系統中,相似的權限控制會不少,這些代碼就好像一顆顆毒瘤通常蔓延於系統中的各處,一旦須要擴展,則給程序員們帶來的困難是不可估量的。 

讓咱們來觀察一下訂單管理業務中的權限管理。不論是添加訂單,仍是刪除訂單,有關權限管理的內容是徹底相同的。那麼,爲何咱們不能將這些相同的業務,抽象爲一個對象,並將其從訂單管理業務中徹底剝離出來呢?在傳統的OO設計思想,這種設想是不能實現的。由於訂單管理業務做爲一個類對象,它封裝了諸如添加、刪除訂單等行爲。這種封裝性,就決定了咱們不可能切入到對象內部,經過獲取方法消息的形式,對對象行爲進行監控與操做。 

AOP的思想解決了這個問題,之因此稱爲「方面(Aspect)」,就是把這些對象剖開,僅獲取其內部相一致的邏輯,並剝離出來,以「方面」的形式存在。要讓這些方面可以對核心業務進行控制,就須要有一套獲取方法消息的機制。在.Net中,其中一種技術稱爲動態代理。 

在.Net中,要實現動態代理,須要用到.Net Remoting中的消息機制,以及.Net Framework內部提供的ContextAttribute類來自定義本身的Attribute。另外,.Net還要求調用「Aspect」的核心業務類,必須繼承ContextBoundObject類。只有這樣,咱們才能截取其內部傳遞的方法消息。如下,是相關接口和類的說明。

ContextAttribute類

該類繼承了Attribute類,它是一個特殊的Attribute,經過它,能夠得到對象須要的合適的執行環境,即Context(上下文)。它還實現了IContextAttribute和IContextProperty接口。咱們自定義的Attribute將從ContextAttribute類派生。

構造函數:

ContextAttribute類的構造函數帶有一個參數,用來設置ContextAttribute的名稱。

公共屬性:

Name:只讀屬性。返回ContextAttribute的名稱

公共方法:

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

IsContextOK:虛擬方法。查詢客戶Context中是否存在指定的屬性。

IsNewContextOK:虛擬方法。默認返回true。一個對象可能存在多個Context,使用這個方法來檢查新的Context中屬性是否存在衝突。

Freeze:虛擬方法。該方法用來定位被建立的Context的最後位置。 

ContextBoundObject類

這個類的對象經過Attribute來指定它所在的Context,凡是進入該Context的調用均可以被攔截。該類從MarshalByRefObject派生。 

IMessage:定義了被傳送的消息的實現。一個消息必須實現這個接口。
IMessageSink:定義了消息接收器的接口,一個消息接收器必須實現這個接口。

該接口主要提供了兩個方法,分別進行同步和異步操做:

SyncProcessMessage(IMessage msg):接口方法,當消息傳遞的時候,該方法被調用;

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

下面是實現權限控制AOP的簡單實現,首先咱們自定義一個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對象,它是一個上下文環境屬性:

    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屬性實現了接口IContextProperty,IContributeObjectSink。GetObjectSink()方法爲IContributeObjectSink接口的方法,在其實現中,建立了一個IMessageSink對象AOPSink,該對象實現了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()方法,在這個方法中,實現了權限控制,並經過IMessage,截取了須要權限控制的方法。在檢驗了權限以後,而後再執行OrderManager的AddOrder和DeleteOrder方法。

 

經過AOP的實現,原來的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類中,徹底消除了permissions.Verify()等有關權限的代碼,解除了訂單管理與權限管理之間的耦合。

 

2、與AspectJ比較

上述的方案雖然解除了訂單管理與權限管理的耦合,但從SyncProcessMessage()方法能夠看出,它的實現具備很大的侷限性。試想一下這樣的應用場景,在訂單管理系統中,用戶要求對修改訂單的方法增長權限驗證,同時要求在驗證權限時,容許業務經理(Permission.Manager)也具有管理訂單的權限,應該怎樣作?仔細思考,咱們會發覺以上的實現未免太過死板了。

 

讓咱們來參考一下AspectJ在java中的實現。AspectJ提供了本身的一套語法,其中包括aspect、pointcut、before、after等。咱們能夠經過aspect定義一個「方面」,如上的權限管理:

private static aspect AuthorizationAspect{……}

 

pointcut爲切入點,在其中定義了須要截取上下文消息的方法,例如:

private pointcut authorizationExecution():

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

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

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

 

因爲權限驗證是在訂單管理方法執行以前完成,所以在before中,定義權限檢查:

before(): authorizationExecution()

{

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

{

    throw new UnauthorizedException();

}

}

從上述AspectJ的實現中,咱們能夠看到,要定義本身的aspect是很是容易的,而經過pointcut的方式,能夠將須要截取消息的方法,集中在一塊兒。before和after則是具體的方面執行的邏輯,它們就好像Decorator模式那樣,對原有方法進行了一層裝飾,從而達到將aspect代碼植入的目的。

 

另外,AspectJ還提供了更簡單的語法,能夠簡化前面pointcut中一系列方法的列舉:

private pointcut authorizationExecution():

execution (public * OrderManager.*(.))

 

AspectJ在應用AOP領域,已經很是成熟。它提供了自成一體的特有AspectJ語法,並須要專門的java編譯器,使用起來較爲複雜。那麼,在.Net下,能否實現相似AspectJ的功能呢?我想,因爲.Net與java在不少技術的類似性,它們彼此之間在不少領域是相通的,所以要達到這一目標應該是可行的。事實上,開源項目中的Aspect#,就與AspectJ類似。

 

事實上,若是咱們利用前面描述的動態代理機制,輔以設計模式的OO設計方法,直接在代碼中也能夠實現AspectJ中的部分AOP特性。

 

3、.Net中AOP的深刻實現

咱們先分析AspectJ中的pointcut和.Net中的SyncProcessMessage()方法。Pointcut能夠添加一系列須要截取上下文的方法,那麼在.Net中,咱們也能夠利用集合,動態地添加方法,並建立這些方法與「方面」的映射。一樣的,AspectJ中的before和after,是「方面」的核心實現,那麼在.Net中,咱們也能夠利用委託,使其對應相關的方法,來實現其核心邏輯。

 

結合動態代理的知識,咱們先定義兩個委託,分別表明before和after操做:

public delegate void BeforeAOPHandle(IMethodCallMessage callMsg);

public delegate void AfterAOPHandle(IMethodReturnMessage replyMsg);

 

BeforeAOPHandle中的參數callMsg,其值爲要截取上下文的方法的消息;AfterAOPHandle中的參數replyMsg,則是該方法執行後返回的消息。

 

接下來,定義一個抽象基類AOPSink,它實現了IMessageSink接口:

public abstract class AOPSink : IMessageSink

    {

        private SortedList m_BeforeHandles;

        private SortedList m_AfterHandles;

        private IMessageSink m_NextSink;

}

在類AOPSink中,定義了兩個SortedList類型的字段:m_BeforeHandles和m_AfterHandles。它們負責存放方法名與BeforeAOPHandle和AfterAOPHandle對象之間的映射。添加這些映射的職責由以下兩個方法完成:

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);

          }

      }

}

考慮到咱們要截取的方法可能會有多個,所以在類AOPSink中,又定義了兩個抽象方法,負責添加全部的映射關係:

protected abstract void AddAllBeforeAOPHandles();

protected abstract void AddAllAfterAOPHandles();

 

而後在構造函數中,咱們初始化兩個SortedList對象,並調用上述的兩個抽象方法:

        public AOPSink(IMessageSink nextSink)

        {

            m_NextSink = nextSink;

            m_BeforeHandles = new SortedList();

            m_AfterHandles = new SortedList();

            AddAllBeforeAOPHandles();

            AddAllAfterAOPHandles();

        }

 

爲了可以根據方法名得到相對應的委託對象,咱們又定義了兩個Find方法。考慮到可能會有多個用戶同時調用,在這兩個方法中,我利用lock避免了對象的爭用:

        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;

        }

接下來是IMessageSink接口要求實現的方法和屬性:

        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()方法。在該方法中,經過FindBeforeAOPHandle()和FindAfterAOPHandle()方法,找到BeforeAOPHandle和AfterAOPHandle委託對象,並執行它們。即執行這兩個委託對象具體指向的方法,相似與AspectJ中的before和after的execution。

 

如今,咱們就能夠象AspectJ那樣定義本身的aspect了。如權限管理一例,咱們定義一個類AuthorizationAOPSink,它繼承了AOPSink:

public class AuthorizationAOPSink : AOPSink

{

    public AuthorizationAOPSink(IMessageSink nextSink)

            : base(nextSink)

   {

   }

}

而後在這個方法中,實現before和after的邏輯。注意before和after方法應與以前定義的委託BeforeAOPHandle和AfterAOPHandle一致。不過,以本例而言,並不須要實現after邏輯:

private void Before_Authorization(IMethodCallMessage callMsg)

{      

        if (callMsg == null)

        {

              return;

        }

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

        {

                 throw UnauthorizedException();

         }

}

而後咱們override基類中的抽象方法AddAllBeforeAOPHandles()和AddAllAfterAOPHandles():

protected override void AddAllBeforeAOPHandles()

        {

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

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

        }

 

        protected override void AddAllAfterAOPHandles()

        {           

        }

由於after邏輯不須要實現,所以重寫AddAllAfterAOPHandles()時,使其爲空就能夠了(必須重寫,由於該方法爲抽象方法)。在AOPProperty類中,須要返回IMessageSink對象,因此還應修改原來的AOPProperty類中的GetObjectSink方法:

public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)

        {

            return new AOPSink(nextSink);

return new AuthorizationAOPSink(nextSink);       

        }

 

比較一下上述的實現方案,自定義的繼承AOPSink類的AuthorizationAOPSink就至關於AspectJ中的aspect。而與BeforeAOPHandle和AfterAOPHandle委託對應的方法,則至關於AspectJ的before和after語法。AddAllBeforeAOPHandles()和AddAllAfterAOPHandle()則至關於AspectJ的pointcut。經過引入委託的方法,使得咱們的AOP實現,具備了AspectJ的一些特性,而這些實現是不須要專門的編譯器的。

 

很明顯,若是咱們要求OrderManager類中新增的UpdateOrder方法,也要加入權限控制,那麼咱們能夠在AddAllBeforeAOPHandles()方法中,增長UpdaeOrder方法與before邏輯的映射:

AddBeforeAOPHandle("UPDATEORDER", Before_Authorization);

一樣的,若是要對權限控制進行修改,開發業務經理對訂單管理的權限,那麼也只須要修改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();

         }

}

 

4、進一步完善

因爲咱們的委託列表m_BeforeHandles和m_AfterHandles爲SortedList類型,所以做爲key的methodName必須是惟一的。若是系統要求添加其餘權限控制的邏輯,例如增長認證功能,就不能再在AuthorizationAOPSink類的AddAllBeforeAOPHandles()方法中增長方法名與認證功能的before邏輯之間的映射了。

private void Before_Authentication(IMessage callMsg){……}

protected override void AddAllBeforeAOPHandles()

{

       ……

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

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

}

若是在AuthorizationAOPSink類中添加上面的代碼,因爲新增的「ADDORDER」key與前面重複,故執行程序時,是找不到相應的委託Before_Authentication的。

 

解決的辦法就是爲認證功能新定義一個aspect。因爲在本方案中,實現AOP功能的不只僅是實現了IMessageSink接口的AOPSink類,同時該類還與Property、Attribute有關。也就是說,若是咱們新定義一個AuthenticationAOPSink,那麼還要定義與之對應的AuthenticationAOPProperty類。爲便於擴展,我採用了Template Method模式,爲全部的property定義了抽象類AOPProperty,其中的抽象方法或虛方法,則留待其子類來實現。

    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

}

與原來的AOPProperty類相比,IContextProperty,IContributeObjectSink接口的方法與屬性,都沒有直接實現,而是在其內部調用了相關的抽象方法和虛方法。包括:抽象方法CreateSink(),虛方法FreezeImpl(),CheckNewContext()以及GetName()。對於其子類而言,須要override的,主要是抽象方法CreateSink()和GetName()(由於Property的Name必須是惟一的),至於其餘虛方法,能夠根據須要選擇是否override。例如,自定義權限控制的屬性類AuthorizationAOPProperty:

    public class AuthorizationAOPProperty :AOPProperty

    {   

        protected override IMessageSink CreateSink(IMessageSink nextSink)

        {

            return new AuthorizationAOPSink(nextSink);

        }

 

        protected override string GetName()

        {

            return "AuthorizationAOP";

        }

    }

在該類中,咱們override了CreateSink()方法,建立了一個AuthorizationAOPSink對象。同時override了虛方法GetName,返回了本身的一個名字「AuthorizationAOP」。

 

關於Attribute類,觀察其方法GetPropertiesForNewContext(),其實現是在IConstructionCallMessage消息的上下文property中添加自定義property。這些property組成了一個鏈,它是能夠靜態添加的。鑑於此,咱們能夠採起兩種策略:

一、 全部的aspect都使用同一個Attribute。其實現以下:

    [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()中,添加多個自定義Property。在添加Property時,須要注意添加Property的順序。

二、 不一樣的aspect使用不一樣的Attribute。此時能夠爲這些Attribute定義一個共同的抽象基類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,目的是不須要其子類在重寫該方法。

 

繼承AOPAttribute類的子類只須要重寫GetAOPProperty()方法便可。但在爲OrderManager類定義Attribute的時候,需注意其順序。如如下的順序:

[AuthorizationAOP]

[AuthenticationAOP]

public class OrderManager{}

此時,AuthorizationAOPAttribute在前,AuthenticationAOPAttribute在後。若是以Decorator的角度來看,對被裝飾的方法,AuthorizationAOPAttribute在內,AuthenticationAOPAttribute在外。

考慮到aspect的應用,有的方法須要多個aspect,有的則只須要單個aspect,因此,第二個方案更佳。

 

5、AOP實例

接下來,我經過一個實例,介紹AOP的具體實現。假定咱們要設計一個計算器,它能提供加法和減法功能。咱們但願,在計算過程當中,可以經過日誌記錄整個計算過程及其結果,同時須要監測其運算性能。該例中,核心業務是加法和減法,而公共的業務則是日誌與監測功能。根據前面對AOP的分析,這兩個功能應爲咱們整個系統須要剝離出來的「方面」。

 

咱們已經擁有了一個AOP實現機制,以及核心的類庫,包括AOPSink、AOPProperty、AOPAttribute三個抽象基類。如今,咱們分別爲日誌aspect和監測aspect,定義相應的Sink、Property、Attribute。

 

首先是日誌aspect:

LogAOPSink.cs:

using System;

using System.Runtime.Remoting.Messaging;

using Wayfarer.AOP;

 

namespace Wayfarer.AOPSample

{

    ///

    /// Summary description for LogAOPSink.

    ///

    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 description for LogAOPProperty.

    ///

    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 description for LogAOPAttribute.

    ///

    [AttributeUsage(AttributeTargets.Class)]

    public class LogAOPAttribute:AOPAttribute

    {

         protected override AOPProperty GetAOPProperty()

         {

             return new LogAOPProperty();

         }

   

    }

}

 

而後再定義監測aspect:

MonitorAOPSink.cs:

using System;

using System.Runtime.Remoting.Messaging;

using Wayfarer.AOP;

 

namespace Wayfarer.AOPSample

{

    ///

    /// Summary description for MonitorAOPSink.

    ///

    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 description for MonitorAOPProperty.

    ///

    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 description for MonitorAOPAttribute.

    ///

    [AttributeUsage(AttributeTargets.Class)]

    public class MonitorAOPAttribute:AOPAttribute

    {

         protected override AOPProperty GetAOPProperty()

         {

             return new MonitorAOPProperty();

         }

    }

}

注意在這兩個方面中,各自的Property的Name必須是惟一的。

如今,能夠定義計算器類。

Calculator.cs:

using System;

 

namespace Wayfarer.AOPSample

{

    ///

    /// Summary description for Calculator.

    ///

    [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類必須繼承ContextBoundObject類。

最後,咱們寫一個控制檯程序來執行Calculator:

Program.cs:

using System;

 

namespace Wayfarer.AOPSample

{

    ///

    /// Summary description for Class1.

    ///

    class Program

    {

         ///

         /// The main entry point for the application.

         ///

         [STAThread]

         static void Main(string[] args)

         {

             Calculator cal = new Calculator();

             cal.Add(3,5);

             cal.Substract(3,5);

             Console.ReadLine();

         }

    }

}

運行結果以下:

aopresult.GIF 

6、結論

在.Net平臺下采用動態代理技術實現AOP,其原理並不複雜,而.Net Framework也提供了足夠的技術來實現它。若是再結合好的設計模式,提供一個基本的AOP框架,將大大地簡化開發人員處理「aspect」的工做。固然,本文雖然提供了實現AOP的實例,但其架構的設計還遠遠不能達到企業級的要求,如在穩定性、可擴展性上還需通過進一步的測試與改善。例如咱們能夠經過配置文件的形式,來配置方法與方面之間的映射。同時,因爲採用了動態代理,在性能上還期待改進。

 

使用動態代理技術實現AOP,對實現AOP的類有一個限制,就是必須派生於ContextBoundObject類,這對於單繼承語言來講,確實是一個比較致命的缺陷。所謂「仁者見仁,智者見智」,這就須要根據項目的狀況,作出正確的抉擇了。

相關文章
相關標籤/搜索