??? 現(xiàn)在我們需要的是這樣一個(gè)框架,它可以方便地引入,且不會(huì)對(duì)原來(lái)的開(kāi)發(fā)和構(gòu)造過(guò)程產(chǎn)生任何影響。滿足這些要求的框架不止一個(gè),例如JBoss AOP、Nanning、Aspectwerkz(AW)。本文選用的是Aspectwerkz,因?yàn)樗赡苁亲钊菀讓W(xué)習(xí)的框架,也是最容易集成到現(xiàn)有項(xiàng)目的框架。
??? Aspectwerkz由Jonas Boner和Alexandre Vasseur創(chuàng)建,它是目前最快速、功能最豐富的框架之一。雖然它還缺乏AspectJ的某些功能,但己足以滿足大多數(shù)開(kāi)發(fā)者在許多情形下的需要。
??? Aspectwerkz最令人感興趣的特性之一是它能夠以兩種不同的模式運(yùn)行:聯(lián)機(jī)模式和脫機(jī)模式。在聯(lián)機(jī)模式下,AW直接干預(yù)屬于JVM的底層類裝入機(jī)制,截取所有的類裝入請(qǐng)求,對(duì)字節(jié)碼實(shí)施即時(shí)轉(zhuǎn)換。AW提供了干預(yù)類裝入過(guò)程的許多選項(xiàng),另外還有一個(gè)替代bin/java命令的封裝腳本,這個(gè)腳本能夠根據(jù)Java版本和JVM能力自動(dòng)生成一組可運(yùn)行的配制。對(duì)于開(kāi)發(fā)者,聯(lián)機(jī)模式有許多優(yōu)點(diǎn),它能插入到任何類裝入器并在類裝入期間生成新的類。也就是說(shuō),我們不必手工修改應(yīng)用程序的類,只要按通常的方式部署即可。不過(guò),聯(lián)機(jī)模式要求對(duì)應(yīng)用服務(wù)器進(jìn)行額外的配制,有時(shí)這一要求可能很難滿足。
??? 在脫機(jī)模式下,生成類需要二個(gè)步驟。第一步是用標(biāo)準(zhǔn)的編譯器編譯,第二步是重點(diǎn)——以脫機(jī)模式運(yùn)行AWcompiler編譯器,讓它處理新生成的類。編譯器將修改這些類的字節(jié)碼,根據(jù)一個(gè)XML文件的定義,在適當(dāng)?shù)?span lang="EN-US">point-cut插入advice。脫機(jī)模式的優(yōu)點(diǎn)是AWcompiler生成的類能夠在任何JVM 1.3以上的虛擬機(jī)運(yùn)行,本文下面要用的就是這種模式,因?yàn)樗恍枰獙?duì)Tomcat作任何修改,只要對(duì)構(gòu)造過(guò)程稍作修改就可以照搬到大多數(shù)現(xiàn)有的項(xiàng)目。
AspectWerkz 主要特性:
??? 1.運(yùn)行時(shí)和加載時(shí)字節(jié)碼修正:你可以在運(yùn)行時(shí)或編譯時(shí)輕松的改造任何(舊)應(yīng)用程序或除了rt.jar以外的外部類庫(kù)
??? 2.支持join point模型
??? 3.支持Annotation:匹配JavaDoc和JSR-175,支持用戶自定義Annotation
??? 4.支持部署多個(gè)Aspect定義文件到部署的應(yīng)用程序(WEB-INF/aop.xml、META-INF/aop.xml)
??? 5.Introduction/內(nèi)類型聲明(也稱Mixin),也就是具有添加接口和實(shí)現(xiàn)到已存在的類中的能力
??? 6.Annotation定義:定義Aspect使用的運(yùn)行時(shí)Annotation(為JSR-175準(zhǔn)備)
??? 7.XML定義:定義Aspect使用的XML;XML可以用來(lái)精煉、改寫(xiě)和解析Annotation定義
??? 8.插件式Aspect管理器能夠和IoC框架(如Spring或PicoContainer)一起工作
??? 9.四種不同的Advice和Introduction部署模型(范圍):perJVM(單模式)、 perClass、perInstance 和perThread
??? 10.Advice和Introduction能夠動(dòng)態(tài)部署、反部署或重新部署
??? 11.高性能,使用JIT編譯
??? 12.使用Fine-grained模式語(yǔ)言選擇join point
??? 13.所有Advice能夠和所有的join point和各種混合類型的pointcut
??? 14.脫機(jī)變換(可以用作后處理器)
??? 15.Aspect、Advice和Introduction使用POJO編碼
??? 16.目標(biāo)類可以是正規(guī)的POJO,也就是不需要接口
??? 17.支持通過(guò)定義傳遞參數(shù)給Advice和定義可重用的Advice堆棧
??? 18.元數(shù)據(jù)被加到類中
??? 19.簡(jiǎn)單的用法和配置
開(kāi)始AOP
1)這里我們要在屏幕打印出“Hello AOP!”,看如下代碼:
//HelloAOP.java
public class HelloAOP {
??? public static void main(String args[]) {
??????? HelloAOP ha = new HelloAOP();
??????? ha.test();
??? }
??? public void test() {
??????? System.out.println("Hello AOP!");
??? }
}
編譯HelloAOP.java文件:javac HelloAOP.java
2)現(xiàn)在我要在輸出“Hello AOP!”前后做一些工作,這些工作在運(yùn)行時(shí)會(huì)得到調(diào)用機(jī)會(huì),如果使用AOP術(shù)語(yǔ),我們可以說(shuō)我們要編寫(xiě)我們的aspect,這個(gè)aspect會(huì)在運(yùn)行時(shí)被weave into (織入)HelloAOP class。
//MyAspect.java
import org.codehaus.aspectwerkz.joinpoint.JoinPoint;
public class MyAspect {
??? public void beforeTesting(JoinPoint joinPoint) {
??? ????System.out.println("before testing...");
??? }
??? public void afterTesting(JoinPoint joinPoint) {
??????? System.out.println("after testing...");
??? }
}
javac MyAspect.java
3)織入過(guò)程并不簡(jiǎn)單,我們需要撰寫(xiě)一個(gè)描述文件來(lái)將aspect和其織入的class中的信息聯(lián)系起來(lái)。
//aop.xml
<aspectwerkz>
??? <system id="AspectWerkzExample">
??????? <aspect class="MyAspect">
??????????????? <pointcut name="testMethod" expression="execution(* HelloAOP.test(..))"/>
??????????????? <advice name="beforeTesting" type="before" bind-to="testMethod"/>
????????????? ??<advice name="afterTesting" type="after" bind-to="testMethod"/>
??????? </aspect>
??? </system>
</aspectwerkz>
4)run it
aspectwerkz -Daspectwerkz.definition.file=aop.xml HelloAOP
//output:
before testing...
Hello AOP!
after testing...