基于.Net的AOP完成技術(shù)
發(fā)表時間:2023-07-21 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]基于.Net的AOP實(shí)現(xiàn)技術(shù) 前言 在筆者的《面向?qū)ο蟮膽?yīng)用服務(wù)層設(shè)計(jì)》一文中,筆者討論了軟件系統(tǒng)中設(shè)計(jì)應(yīng)用服務(wù)層所需要考慮的問題,以及系統(tǒng)分層的基本思考方法。這些討論作關(guān)注的問題,都是系統(tǒng)中縱向的...
基于.Net的AOP實(shí)現(xiàn)技術(shù)
前言
在筆者的《面向?qū)ο蟮膽?yīng)用服務(wù)層設(shè)計(jì)》一文中,筆者討論了軟件系統(tǒng)中設(shè)計(jì)應(yīng)用服務(wù)層所需要考慮的問題,以及系統(tǒng)分層的基本思考方法。這些討論作關(guān)注的問題,都是系統(tǒng)中縱向的層次的劃分。然而,在設(shè)計(jì)軟件系統(tǒng)的時候,我們不僅僅要考慮縱向的關(guān)系,很多時候,我們還需要關(guān)注所謂的“橫切關(guān)注點(diǎn)”的問題,例如,存在于系統(tǒng)每個部分的日志記錄、安全性驗(yàn)證等。AOP(面向方面編程)的出現(xiàn),便是為了解決這些“橫切關(guān)注點(diǎn)”的問題。
雖然AOP目前還不是如OOP般非常成熟,但是,也已經(jīng)有數(shù)個支持AOP的產(chǎn)品問世,其中比較有名的有AspectJ,AspectWerkz等,這些產(chǎn)品都基于Java平臺。在.Net平臺上,也有一些實(shí)現(xiàn),如LOOM等,但是,相對于Java平臺的實(shí)現(xiàn),這些實(shí)現(xiàn)都還很不成熟,功能也比較弱,使用上也不是很方便。因此,筆者在.Net平臺下自己實(shí)現(xiàn)了一個輕量級的AOP框架,現(xiàn)在拿出來同大家共同探討。
在本文中,筆者將首先歸納一下目前實(shí)現(xiàn)AOP的基本手段,然后,給出一個已經(jīng)實(shí)現(xiàn)的AOP的范例(WebsharpAspect),并提供全部源代碼,這是一個輕量級的AOP實(shí)現(xiàn),雖然目前功能還不是很強(qiáng)大,實(shí)現(xiàn)也比較簡單,但是,他已經(jīng)可以完成大部分我們所需要的AOP功能,你可以在項(xiàng)目中直接使用他。重要的是,其中展示了在.Net環(huán)境下實(shí)現(xiàn)AOP的一些技術(shù)和思路,筆者也希望通過提供源代碼的方式,能夠?qū)Υ蠹覍W(xué)習(xí)AOP有所助益。
實(shí)現(xiàn)AOP的方法
實(shí)現(xiàn)AOP的關(guān)鍵,是攔截正常的方法調(diào)用,將我們需要額外附加的功能透明的“織入”到這些方法中,以完成一些額外的要求。從總體方法上來說,織入的方法有兩大類:靜態(tài)織入和動態(tài)織入。
靜態(tài)織入方法,一般都是需要擴(kuò)展編譯器的功能,將需要織入的代碼,通過修改字節(jié)碼(Java)或者IL代碼(.Net)的方法,直接添加到相應(yīng)的被織入點(diǎn);或者,我們需要為原來語言添加新的語法結(jié)構(gòu),從語法上支持AOP。AspectJ就是采用的這種方式。使用這種方式來實(shí)現(xiàn)AOP,其優(yōu)點(diǎn)是代碼執(zhí)行的效率高,缺點(diǎn)是實(shí)現(xiàn)者需要對虛擬機(jī)有很深的了解,才能夠做到對字節(jié)碼修改。由于織入方法是靜態(tài)的,當(dāng)需要添加新的織入方法時,往往需要重新編譯,或者說運(yùn)行字節(jié)碼增強(qiáng)器重新執(zhí)行靜態(tài)織入的方法。當(dāng)然,在.Net平臺上,我們也可以使用Emit提供的強(qiáng)大功能來實(shí)現(xiàn)這一點(diǎn)。另外,字節(jié)碼增強(qiáng)器帶來了很大的不透明性,程序員很難直觀的調(diào)試增強(qiáng)后的字節(jié)碼,因此很多程序員總是在心理上抵制這種字節(jié)碼增強(qiáng)器。
動態(tài)織入的方法,具體實(shí)現(xiàn)方式就有很多選擇了。在Java平臺上,可以使用Proxy模式,或者定制ClassLoader來實(shí)現(xiàn)AOP功能。在.Net平臺上,要實(shí)現(xiàn)AOP的動態(tài)織入,歸納起來,可以采用以下幾種方法:
l 使用ContextAttribute和ContextBoundObject來對對象的方法進(jìn)行攔截。關(guān)于ContextAttribute的具體使用方法,讀者可以參考MSDN等相關(guān)資料。
l 使用Emit來,在運(yùn)行時刻動態(tài)構(gòu)建被織入代碼后的類,當(dāng)程序調(diào)用被織入類時,實(shí)際上調(diào)用的是被修改后的類。LOOM使用的就是這種方式,但是,個人認(rèn)為,LOOM目前的實(shí)現(xiàn)非常生硬,其可擴(kuò)展性和靈活性都不是很好。
l 使用Proxy模式。這也是本文將詳細(xì)介紹的方法。
l 當(dāng)然,在ASP.Net項(xiàng)目中,我們還有一種選擇,就是使用HTTPHandler和HTTPModule來對自定義對ASP.Net頁面的訪問,加入一些我們需要的處理。關(guān)于如何使用HTTPHandler和HTTPModule的內(nèi)容,可以參考筆者的文章《ASP.Net中自定義Http處理及應(yīng)用之HttpHandler篇》,以及《ASP.Net中自定義Http處理及應(yīng)用之HttpModule篇》
下面,我們來探討如何使用Proxy模式,在.Net平臺上實(shí)現(xiàn)一個可用的AOP框架。
第一個例子
首先,我們來看看WebsharpAspect的使用效果。我們可以使用以下步驟來完成我們的第一個例子的編寫:
1、 在VisualStudio中新建一個控制臺應(yīng)用程序,把Websharp.Aspect.dll添加入引用。
2、 添加一個類,命名為FirstAspect,并使他實(shí)現(xiàn)IAspect接口,添加代碼如下:
public class FirstAspect : IAspect
{
public void Execute(object[] paramList)
{
Console.WriteLine("FirstAspect is called");
}
}
3、 添加一個BusinessClass類,模擬具體的業(yè)務(wù)邏輯類,使這個類繼承AspectObject類,并添加AspectManaged特性,然后添加兩個方法,代碼如下:
[AspectManaged(true)]
public class BusinessClass : AspectObject
{
public BusinessClass(){}
public void OutputMethod()
{
Console.WriteLine("OutputMethod()");
}
public void GetString()
{
Console.WriteLine("GetString()");
}
}
4、 為項(xiàng)目添加一個App.config配置文件,,并且添加以下內(nèi)容:
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
< configSections >
<sectionname="Websharp.Aspects"type="Websharp.Aspect.AspectConfigHandler,Websharp.Aspect"/>
</ configSections >
< Websharp.Aspects >
< Aspect type ="WeaveTest.FirstAspect,WeaveTest" deploy-model ="Singleton"
pointcut-type="Method Construction"action-position="Both"match="*,*"/>
</ Websharp.Aspects >
</configuration>
5、 在Main方法中添加如下代碼:
public class MainClass
{
[STAThread]
static void Main ()
{
BusinessClass cls=new BusinessClass();
cls.OutputMethod();
cls.GetString();
Console.ReadLine();
}
}
運(yùn)行以上代碼,其結(jié)果如下:
可以看到,F(xiàn)irstAspect如我們所預(yù)期的那樣,成功的攔截了BusinessClass的方法。