程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> AOP解析:含簡單AOP框架實現(包括Proxy模式實現與Attribute實現)

AOP解析:含簡單AOP框架實現(包括Proxy模式實現與Attribute實現)

編輯:關於.NET

AOP簡介:

AOP(Aspect Oriented Programming)“面向切面編程”,其實和OOP(Object Oriented Programming)“面向對象編程”一樣是一種編程思路,而且個人以為翻譯為“切面導向編程 ”更為妥當,OOP也應翻譯為“對象導向編程”。因為正是有了“切面”和“對象”的想法和 概念才產生了“Aspect Oriented Programming”和“Object Oriented Programming”這些 編程方法,所以“導向”更為貼近些。

以下想法均為個人揣摩得出,具體官方概念請Google,Bing,Baidu.

AOP,個人以為是一種行為(Behavior)的注入,在不改變原有邏輯(original logic) 的基礎上,將一些可重用的其他邏輯(other logic)注入到原有邏輯(original logic)中 。切面(Aspect)即為其他邏輯(other logic),是一些特殊的業務關注點,包括“事務處理 ”,“異常捕捉”,“日志記錄”,“身份驗證”等方面。

這種“切面”邏輯一般貫徹整個解決方案,AOP方式將這種切面提取出來,實現了解耦和 代碼簡潔化。

簡單例子:

下面舉個簡單的例子來說明為什麼要使用AOP:

1)沒有使用AOP的Castle ActiveRecord“事務處理”

class AOPTest
{
     // ......
     /// <summary>
     /// Save the retire user info.
     /// </summary>
     /// <param name="site">The user will be retire  user.</param>
     public void SaveRetireUserInfo(User user)
     {
         using(TransactionScope transaction = new TransactionScope ())
         {
            try
            {
              RetireUser retireUser = new RetireUser();
              retireUser.Name = user.Name;
              retireUser.Department = user.Department;
              // ...
              user.Delete();
              retireUser.Save();
              transaction.VoteCommit(); //完成事務
            }
            catch(Exception ex)
            {
               Log.Write(ex.Message);
               transaction.VoteRollBack(); //事務回滾
            }
         }
     }
     // ......
}

2)使用AOP的Castle ActiveRecord“事務處理”, 裡邊使用了我自己寫的精簡AOP框架, 與原來的文章一樣,看不懂沒關系,這裡只是個宏觀的概念。重點在demo分析。

/// <summary>
/// The test class for AOP use attribute for transaction.
/// </summary>
[AOPProxy(Interception = typeof(TransactionInterception))]
class AOPTest : ContextBoundObject
{
     // ......
     /// <summary>
     /// Save the retire user info.
     /// </summary>
     /// <param name="site">The user will be retire  user.</param>
     public void SaveRetireUserInfo(User user)
     {
         RetireUser retireUser = new RetireUser();
         retireUser.Name = user.Name;
         retireUser.Department = user.Department;
         // ...
         user.Delete();
         retireUser.Save();
     }
     // ......
}

/// <summary>
/// The interception of the AOP for trasaction.
/// </summary>
class TransactionInterception : IInterception
{
     private TransactionScope transaction = null;
     #region IInterception Members
     public void ExceptionHandle()
     {
         transaction.VoteRollBack(); //事務回滾
     }
     public void PostInvoke()
     {
         transaction.VoteCommit(); //完成事務
     }
     public void PreInvoke()
     {
         transaction = new TransactionScope(); //初始化事務
     }
     #endregion
}

由以上可見,加入AOP後(AOPProxy Attribute實現),“其他邏輯”注入“原始邏輯” 使得代碼更加簡潔,同時也將“切面”的邏輯和“業務”的邏輯分離開來,實現了解耦。 TransactionInterception是攔截器,實現了“其他邏輯”,由AOPProxy Attribute通過type 將其注入。在處理“原始邏輯”的時候會同時處理注入的“其他邏輯”。ExceptionHandle方 法實現出現 Exception時的“其他邏輯”注入;PreInvoke方法實現在調用“主題”方法前的 “其他邏輯”注入;PostInvoke方法實現在調用“主題”方法後的“其他邏輯”注入。

簡單來說執行流程如下:

1. PreInvoke();

2. 主題Method();

3.if(調用"主題Method()"時出現Exception)

{
      ExceptionHandle();
}
else
{
      PostInvoke();
}

有下面的SaveRetireUserInfo方法可以看到“業務邏輯”變得簡潔,在“業務邏輯”已經 見不到擾亂代碼可讀性的“事務代碼”和 “try...catch...”語句塊了,只需要給該類加上 “AOPProxy”特性注入相應的“攔截器”並繼承ContextBoundObject 即可。

public void SaveRetireUserInfo(User user)
{
         RetireUser retireUser = new RetireUser();
         retireUser.Name = user.Name;
         retireUser.Department = user.Department;
         // ...
         user.Delete();
         retireUser.Save();
  }

Proxy基礎:

代理模式,說白了就是設置一個“中間層”(proxy),把對實際要操作的“主題”保護 在裡邊,並且在操作時進行額外的操作,實現注入。對“主題”的操作均需要通過proxy來完 成,就如同經濟人。

比如:你是著名歌星SexyBaby,你有一個經紀人叫Underdog,你只負責唱歌,各種演唱會 的舉辦和電視台對你邀請一律由Underdog負責,你SexyBaby就是“主題”而你的經紀人 Underdog就是proxy。

具體的代理模式可以看我以前寫的關於Dota的設計模式隨筆和各種設計模式書籍。

下面介紹個簡單的例子來了解下代理模式。

假設一個場景:IT界優秀人士均喜歡看AV,而由於為了保護我們國家未成年人幼小的心靈 不受到不良網站侵害,國家屏蔽了AV站點,那我們這些IT界寂寞哥又有這樣的需求,那該怎 麼辦那?我們需要通過Online Web Proxy來解決這個問題,我們通過這樣的“在線代理網站 ”(“在線代理網站”服務器放在不屏蔽AV站點的國家,由“在線代理網站”服務器間接訪 問AV站點。因為在線代理網站不直接提供AV信息,所以我們是可以訪問的)來訪問AV站點就 可以了。這時我們是通過Proxy(“在線代理網站”)訪問到“主題” (AV站點),對Proxy (“在線代理網站”)的操作和直接操作“主題”(AV站點)沒有什麼區別。

下面就開始我們的AV之旅吧,由於上次有同學說我代碼裡用中文,怪怪的,這次都用英文 ,順便讓大家復習下英文了:

1) 首先我們必須有一台鏈接到Internet的電腦“MyComputer”。

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// My PC.
     /// </summary>
     public class MyComputer
     {
         /// <summary>
         /// Visit the site.
         /// </summary>
         /// <param name="site">The site.</param>
         public void Visit(ISite site)
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("Site Url:{0}", site.Url);
             Console.ForegroundColor = ConsoleColor.White;
             IFilter filter = new ChinaDNSFilter(); // Server  in China, comply with the rule of China.
             site = filter.Parse(site); // Parse the  site.
             Console.ForegroundColor = ConsoleColor.Gray;
             site.ShowInformation(); // Show the information  of the site.
             Console.ForegroundColor = ConsoleColor.White;
         }
     }
}

“MyComputer”有一個Visit方法,可以訪問到傳入的ISite(抽象出的站點接口), Visit方法流程如下:

1) 輸出當前站點ISite的Url。下面的Code是ISite的定義。

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The interface of site.
     /// </summary>
     public interface ISite
     {
         /// <summary>
         /// The url of site.
         /// </summary>
         string Url
         {
             get;
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         void ShowInformation();
     }
}

另外我們設計了幾個站點以供訪問,代碼如下:

首先是傳說中的AVSite(http://www.avsite.com/),看看介紹多麼吸引人“The site is so hot, all AV stars.”。

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The site contains AV information.
     /// </summary>
     public class AVSite : ISite
     {
         #region ISite Members
         /// <summary>
         /// The url of site.
         /// </summary>
         public string Url
         {
             get { return "http://www.AVSite.com"; }
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         public void ShowInformation()
         {
             Console.WriteLine("The site is so hot, all AV  stars.");
         }
         #endregion
     }
}

然後是我們經常上的博客園“http://www.cnblogs.com”,介紹“The technology site, the home of coders.”。

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The site of cnblogs.
     /// </summary>
     public class CnblogsSite : ISite
     {
         #region ISite Members
         /// <summary>
         /// The url of site.
         /// </summary>
         public string Url
         {
             get { return "http://www.cnblogs.com"; }
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         public void ShowInformation()
         {
             Console.WriteLine("The technology site, the home  of coders.");
         }
         #endregion
     }
}

下面該我們的主角出場了,“在線代理網站”“http://www.myproxy.com”。我們可以通 過構造函數傳入想要代理訪問的站點地址,傳入站點地址後會通過DNS解析訪問到相應的網站 。“在線代理網站”和“DNS(Domain Name Resolution)”的實現(執行“在線代理網站” 的ShowInformation方法時實際是通過代理顯示要代理網站(AV站點)的信息)。

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The online web proxy site.
     /// </summary>
     public class MyProxySite : ISite
     {
         private ISite _site = null;
         public MyProxySite(string url)
         {
             _site = DNS.GetSite(url);
         }
         #region ISite Members
         /// <summary>
         /// The url of site.
         /// </summary>
         public string Url
         {
             get { return "http://www.myproxy.com"; }
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         public void ShowInformation()
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("Proxy start!");
             Console.WriteLine("Real url:{0}", _site.Url);
             Console.ForegroundColor = ConsoleColor.Gray;
             IFilter filter = new USADNSFilter(); // Server  in USA, comply with the rule of USA.
             _site = filter.Parse(_site);
             _site.ShowInformation();
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("Proxy end!");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         #endregion
     }
}

DNS

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// Domain name resolution.
     /// </summary>
     class DNS
     {
         /// <summary>
         /// Get the site instance by the url.
         /// </summary>
         /// <param name="url">The visited  url.</param>
         /// <returns>The site instance.</returns>
         public static ISite GetSite(string url)
         {
             ISite site = null;
             if (url == "http://www.AVSite.com")
             {
                 site = new AVSite();
             }
             else if (url == "http://www.cnblogs.com")
             {
                 site = new CnblogsSite();
             }
             else
             {
                 site = new NullSite();
             }
             return site;
         }
     }
}

另外當DNS中不包含傳入的網址時要返回“NullSite”,用“MyComputer”直接訪問 “AVSite”時,會被 “ChinaFilter”過濾,返回“WarnningSite”提醒訪問者觸犯法律。 “NullSite”和“WarnningSite”實現如下。

NullSite:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The site with nothing.
     /// </summary>
     public class NullSite : ISite
     {
         #region ISite Members
         /// <summary>
         /// The url of site.
         /// </summary>
         public string Url
         {
             get { return String.Empty; }
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         public void ShowInformation()
         {
             Console.WriteLine("No site, please check the  url.");
         }
         #endregion
     }
}

WarnningSite:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The site for the warnning of gov.
     /// </summary>
     public class WarnningSite : ISite
     {
         #region ISite Members
         /// <summary>
         /// The url of site.
         /// </summary>
         public string Url
         {
             get { return String.Empty; }
         }
         /// <summary>
         /// Show the information about this site.
         /// </summary>
         public void ShowInformation()
         {
             Console.WriteLine("For the gov rule, this site  can't be visited.");
         }
         #endregion
     }
}

2) 根據中國法律由ISP(Internat Service Provider)服務器過濾網站,返回相應的站 點對象。

過濾接口實現如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// The interface of the site visiting filter.
     /// </summary>
     public interface IFilter
     {
         /// <summary>
         /// Parse the site.
         /// </summary>
         /// <param name="site">The site.</param>
         /// <returns>The new site.</returns>
         ISite Parse(ISite site);
     }
}

中國過濾器,過濾掉AVSite,過濾後返回WarnningSite,實現如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// ISP(Internet Service Provider),filter the visited site  information for comply the rule of China.
     /// </summary>
     public class ChinaDNSFilter : IFilter
     {
         #region IFilter Members
         /// <summary>
         /// Parse the site.
         /// </summary>
         /// <param name="site">The site.</param>
         /// <returns>The new site.</returns>
         public ISite Parse(ISite site)
         {
             // For the children, no AV information.
             ISite returnSite = site;
             if (site is AVSite)
             {
                 returnSite = new WarnningSite();
             }
             return returnSite;
         }
         #endregion
     }
}

美國過濾器,不過濾AVSite,直接返回AVSite,實現如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.ProxyPattern
{
     /// <summary>
     /// ISP(Internet Service Provider),filter the visited site  information for comply the rule of USA.
     /// </summary>
     class USADNSFilter : IFilter
     {
         #region IFilter Members
         /// <summary>
         /// Parse the site.
         /// </summary>
         /// <param name="site">The site.</param>
         /// <returns>The new site.</returns>
         public ISite Parse(ISite site)
         {
             // Freedom, no filter.
             return site;
         }
         #endregion
     }
}

3) 通過_site.ShowInformation顯示站點信息。

虛擬Internat已經搭建起來,可以進行測試啦。

首先用“MyComputer”直接訪問AVSite,返回WarnningSite:

MyComputer myComputer = new MyComputer();
  ISite site = new AVSite();
  myComputer.Visit(site); // Visit AV site will be return  warning.

結果:

然後用“MyComputer”通過“MyProxySite”在線代理網站,代理訪問AVSite,返回 AVSite站點信息,偶也~~~~

site = new MyProxySite("http://www.avsite.com/"); // Use online  web proxy.
myComputer.Visit(site);

結果:

最後看完AV,我們再會博客園逛一逛

site = new CnblogsSite();
myComputer.Visit(site);

結果:

花了很大的功夫說代理,現在該切入正題了,我們的AOP,分為代理模式實現和Attribute 實現。

AOP框架實現

首先AOP實現了邏輯注入,即在調用方法之前進行了邏輯注入。我們使用 System.Runtime.Remoting中呃Message機制來實現Message的截獲和注入,有點像MFC框架中 的鉤子函數。

首先,為了實現邏輯注入,我們先要設計出邏輯注入的接口(IInterception)。為了簡 單起見邏輯注入我們只設計了3個Method,包括 PreInvoke,PostInvoke和ExceptionHandle ,分別用來注入“調用主題Method前的邏輯”,“調用主題Method後的邏輯”和“調用主題 Method時發生Exception的邏輯”。具體實現如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
namespace Landpy.AOP
{
     /// <summary>
     /// Description of IInterception.
     /// </summary>
     public interface IInterception
     {
         /// <summary>
         /// Pre the method invoke.
         /// </summary>
         void PreInvoke();
         /// <summary>
         /// Post the method invoke.
         /// </summary>
         void PostInvoke();
         /// <summary>
         /// Handling the exception which occurs when the  method is invoked.
         /// </summary>
         void ExceptionHandle();
     }
}

邏輯注入的接口(IInterception)永遠不為null,根據Null Object模式設計了 NullInterception(關於Null Object模式及其意義可以看我原來的文章),實現如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.AOP
{
     /// <summary>
     /// Null Object pattern for interception.
     /// </summary>
     public class NullInterception : IInterception
     {
         #region IInterception Members
         /// <summary>
         /// Before invoke the real instance to do  something.
         /// </summary>
         public virtual void PreInvoke()
         {
             // Do nothing.
         }
         /// <summary>
         /// End invoke the real instance to do something.
         /// </summary>
         public virtual void PostInvoke()
         {
             // Do nothing.
         }
         /// <summary>
         /// Handling the exception which occurs when the  method is invoked.
         /// </summary>
         public void ExceptionHandle()
         {
             // Do nothing.
         }
         #endregion
     }
}

為了實現Message攔截,我們必須實現一個繼承了“RealProxy”的類“AOPRealProxy”, 這樣我們就可以重寫 System.Runtime.Remoting.Messaging.IMessage Invoke (System.Runtime.Remoting.Messaging.IMessage msg)方法來注入自己的邏輯。

有的時候代碼能更清楚的表達,所以先將AOPRealProxy的實現附上:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Activation;
namespace Landpy.AOP
{
     /// <summary>
     /// RealProxy is a abstract class, which is a class in  Framework to provide the function about base proxy.
     /// The Invoke method like the hook of MFC, it intercept  the message, inject the custom logic and generate a new message
     /// for system to performance.
     /// </summary>
     class AOPRealProxy : RealProxy, IProxyDI
     {
         private MarshalByRefObject _target = null;
         private IInterception _interception = null;
         public AOPRealProxy(Type targetType, MarshalByRefObject  target)
             : base(targetType)
         {
             _target = target;
             _interception = new NullInterception();
         }
         /// <summary>
         /// Overridden the method "Invoke" of the base class,  invokes the method that is specified
         //  in the provided  System.Runtime.Remoting.Messaging.IMessage on the remote
         //  object that is represented by the current  instance.
         /// </summary>
         /// <param name="msg">A  System.Runtime.Remoting.Messaging.IMessage that contains a  System.Collections.IDictionary
         //  of information about the method call.
         //  </param>
         /// <returns>The message returned by the invoked  method, containing the return value and
         //  any out or ref parameters.
         //  </returns>
         public override System.Runtime.Remoting.Messaging.IMessage  Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
         {
             IMethodReturnMessage methodReturnMessage =  null;
             IMethodCallMessage methodCallMessage = msg as  IMethodCallMessage;//Check whether the message is method call message.
             if (methodCallMessage != null)
             {
                 IConstructionCallMessage  constructionCallMessage = methodCallMessage as IConstructionCallMessage;
                 if (constructionCallMessage != null)  //Constructor Method.
                 {
                     RealProxy defaultProxy =  RemotingServices.GetRealProxy(_target);
                     defaultProxy.InitializeServerObject (constructionCallMessage);
                     methodReturnMessage =  EnterpriseServicesHelper.CreateConstructionReturnMessage(constructionCallMessage,  (MarshalByRefObject)GetTransparentProxy()); //Create the message about  constructor.
                 }
                 else //Other method except constructor  method.
                 {
                     _interception.PreInvoke(); //Inject  PreInvoke method.
                     try
                     {
                         methodReturnMessage =  RemotingServices.ExecuteMessage(_target, methodCallMessage); //Invoke subject  method.
                     }
                     catch
                     {
                     }
                     if (methodReturnMessage.Exception !=  null)
                     {
                         _interception.ExceptionHandle (); //Occur exception and then inject ExceptionHandle method.
                     }
                     else
                     {
                         _interception.PostInvoke();  //Inject PostInvoke method.
                     }
                 }
             }
             return methodReturnMessage;
         }
         #region IProxyDI Members
         /// <summary>
         /// Dependency injection the interception into proxy  class.
         /// </summary>
         /// <param name="interception">The  interception.</param>
         public void InterceptionDI(IInterception interception)
         {
             _interception = interception; //The pattern of  interface inject, inject the interception.
         }
         #endregion
     }
}

使用接口注入方式,將Interception“攔截器”注入到“AOPRealProxy”類。

注入接口“IProxyDI”設計如下:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.AOP
{
     interface IProxyDI
     {
         void InterceptionDI(IInterception interception);
     }
}

1) 實現Proxy模式AOP:

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Collections.Generic;
using System.Text;
namespace Landpy.AOP
{
     public class ProxyFactory
     {
         public static T CreateProxyInstance<T>(IInterception  interception) where T : new()
         {
             Type serverType = typeof(T);
             MarshalByRefObject target =  Activator.CreateInstance(serverType) as MarshalByRefObject;
             AOPRealProxy aopRealProxy = new AOPRealProxy (serverType, target);
             aopRealProxy.InterceptionDI(interception);
             return (T)aopRealProxy.GetTransparentProxy();
         }
     }
}

實現了interception參數注入AOPRealProxy,將包裝完成的傳輸代理類返回。此時返回的 代理類對象操作起來如同直接操作“主題”。

2)實現Attribute模式AOP

//
// Authors:
// Xiaoliang Pang (mailto:[email protected])
//
// Copyright (c) 2010 Landpy Software
//
// http://www.cnblogs.com/pangxiaoliang
//
using System;
using System.Runtime.Remoting.Proxies;
namespace Landpy.AOP
{
     /// <summary>
     /// Description of AOPProxyAttribute.
     /// </summary>
     [AttributeUsage(AttributeTargets.Class)]
     public class AOPProxyAttribute : ProxyAttribute
     {
         private IInterception _interception;
         public Type Interception
         {
             get 
             {
                 return _interception.GetType();
             }
             set
             {
                 IInterception interception =  Activator.CreateInstance(value) as IInterception;
                 _interception = interception;
             }
         }
         public AOPProxyAttribute()
         {
             _interception = new NullInterception();
         }
         public override MarshalByRefObject CreateInstance(Type  serverType)
         {
             MarshalByRefObject target = base.CreateInstance (serverType);
             AOPRealProxy aopRealProxy = new AOPRealProxy (serverType, target);
             aopRealProxy.InterceptionDI(_interception);
             return aopRealProxy.GetTransparentProxy() as  MarshalByRefObject;
         }
     }
}

實現了interception的Attribute用type注入AOPRealProxy,將包裝完成的傳輸代理類返 回。此時返回的代理類對象操作起來如同直接操作“主題”。

測試AOP框架

(一)測試代理模式AOP。

// Proxy class to implement the AOP.
IInterception interception = new MyInterception();
AOPTestWithProxyClass aopTestTwo =  ProxyFactory.CreateProxyInstance<AOPTestWithProxyClass>(interception) as  AOPTestWithProxyClass;
aopTestTwo.Show();

首先實例化了一個MyInterception的攔截器,然後用ProxyFactory將Interception作為傳 入注入“主題”。

MyInterception實現如下:

/// <summary>
     /// The interception of the AOP.
     /// </summary>
     class MyInterception : IInterception
     {
         #region IInterception Members
         /// <summary>
         /// Before invoke the real instance to do  something.
         /// </summary>
         public void PreInvoke()
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("===Pre MyInterception.===");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         /// <summary>
         /// End invoke the real instance to do something.
         /// </summary>
         public void PostInvoke()
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("===Post MyInterception.===");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         /// <summary>
         /// Handling the exception which occurs when the  method is invoked.
         /// </summary>
         public void ExceptionHandle()
         {
             Console.ForegroundColor = ConsoleColor.Red;
             Console.WriteLine("There is a exception!");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         #endregion
     }

AOPTestWithProxyClass實現如下:

/// <summary>
     /// The test class for AOP use proxy class.
     /// </summary>
     class AOPTestWithProxyClass : ContextBoundObject
     {
         public void Show()
         {
             Console.ForegroundColor = ConsoleColor.Gray;
             Console.WriteLine("Hello, I am AOPTestTwo.");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
     }

結果:

可見"===Pre MyInterception.==="和"===Post MyInterception.==="已經成功實現AOP 注入。

(二)測試Attribute實現AOP。

// Attribute to implement the AOP.
AOPTestWithAttribute aopTest = new AOPTestWithAttribute();
aopTest.Show();

此時的代碼要比Proxy實現更為簡單,直接用類的構造函數實現類的實例化,不用 ProxyFactory生成實例,Interception同樣還是使用了MyInterception。

AOPTestWithAttribute類的實現如下:

/// <summary>
     /// The test class for AOP use attribute..
     /// </summary>
     [AOPProxy(Interception = typeof(MyInterception))]
     class AOPTestWithAttribute : ContextBoundObject
     {
         public void Show()
         {
             Console.ForegroundColor = ConsoleColor.Gray;
             Console.WriteLine("Hello, I am AOPTest.");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
     }

結果:

(三)測試Attribute實現AOP[事務的提交和回滾]。

AOPTestWithAttributForTrasaction aopTestWithAttributForTrasaction =  new AOPTestWithAttributForTrasaction();
             // Execute the transaction successfully.
             aopTestWithAttributForTrasaction.ExecuteTransactionSuccessfully();
             WriteSplitLine();
             // Execute the transaction unsuccessfully.
             try
             {   
                 aopTestWithAttributForTrasaction.ExecuteTransactionUnsuccessfully();
             }
             catch (Exception ex)
             {
                 Console.ForegroundColor =  ConsoleColor.Blue;
                 Console.WriteLine(ex.Message);
                 Console.ForegroundColor =  ConsoleColor.Gray;
             }

在ExecuteTransactionUnsuccessfully方法中加入throw Excetpion代碼,實現執行不成 功的情況。當執行ExecuteTransactionSuccessfully方法時實現事務的提交,當執行 ExecuteTransactionUnsuccessfully實現事務的回滾,此時的例子可以對照前面所將的 Castle ActiveRecord的事務實現AOP的例子。

AOPTestWithAttributForTrasaction實現如下:

[AOPProxy(Interception = typeof(TransactionInterception))]
     class AOPTestWithAttributForTrasaction : ContextBoundObject
     {
         public void ExecuteTransactionSuccessfully()
         {
             Console.WriteLine("Execute the transaction  successfully:)");
         }
         public void ExecuteTransactionUnsuccessfully()
         {
             Console.WriteLine("Execute the transaction  unsuccessfully:(");
             throw new AOPNullException();
         }
     }

Interception使用了新的TransactionInterception,TransactionInterception的實現如 下:

/// <summary>
     /// The interception of the AOP for trasaction.
     /// </summary>
     class TransactionInterception : IInterception
     {
         #region IInterception Members
         public void ExceptionHandle()
         {
             Console.ForegroundColor = ConsoleColor.Red;
             Console.WriteLine("☆☆☆Rollback transaction☆☆ ☆");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         public void PostInvoke()
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("☆☆☆Commit transaction☆☆ ☆");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         public void PreInvoke()
         {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("☆☆☆Begin transaction☆☆ ☆");
             Console.ForegroundColor = ConsoleColor.Gray;
         }
         #endregion
     }

結果:

注意:在Debug下執行到“throw new AOPNullException();”時會停止,繼續F5即可執行 ,如果非Debug狀態(如直接雙擊exe執行),則可以執行到結束。

這是由Debug機制造成的,不必在意。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved