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機制造成的,不必在意。