??? 現在我們需要的是這樣一個框架,它可以方便地引入,且不會對原來的開發和構造過程產生任何影響。滿足這些要求的框架不止一個,例如JBoss AOP、Nanning、Aspectwerkz(AW)。本文選用的是Aspectwerkz,因為它可能是最容易學習的框架,也是最容易集成到現有項目的框架。
??? Aspectwerkz由Jonas Boner和Alexandre Vasseur創建,它是目前最快速、功能最豐富的框架之一。雖然它還缺乏AspectJ的某些功能,但己足以滿足大多數開發者在許多情形下的需要。
??? Aspectwerkz最令人感興趣的特性之一是它能夠以兩種不同的模式運行:聯機模式和脫機模式。在聯機模式下,AW直接干預屬于JVM的底層類裝入機制,截取所有的類裝入請求,對字節碼實施即時轉換。AW提供了干預類裝入過程的許多選項,另外還有一個替代bin/java命令的封裝腳本,這個腳本能夠根據Java版本和JVM能力自動生成一組可運行的配制。對于開發者,聯機模式有許多優點,它能插入到任何類裝入器并在類裝入期間生成新的類。也就是說,我們不必手工修改應用程序的類,只要按通常的方式部署即可。不過,聯機模式要求對應用服務器進行額外的配制,有時這一要求可能很難滿足。
??? 在脫機模式下,生成類需要二個步驟。第一步是用標準的編譯器編譯,第二步是重點——以脫機模式運行AWcompiler編譯器,讓它處理新生成的類。編譯器將修改這些類的字節碼,根據一個XML文件的定義,在適當的point-cut插入advice。脫機模式的優點是AWcompiler生成的類能夠在任何JVM 1.3以上的虛擬機運行,本文下面要用的就是這種模式,因為它不需要對Tomcat作任何修改,只要對構造過程稍作修改就可以照搬到大多數現有的項目。
AspectWerkz 主要特性:
??? 1.運行時和加載時字節碼修正:你可以在運行時或編譯時輕松的改造任何(舊)應用程序或除了rt.jar以外的外部類庫
??? 2.支持join point模型
??? 3.支持Annotation:匹配JavaDoc和JSR-175,支持用戶自定義Annotation
??? 4.支持部署多個Aspect定義文件到部署的應用程序(WEB-INF/aop.xml、META-INF/aop.xml)
??? 5.Introduction/內類型聲明(也稱Mixin),也就是具有添加接口和實現到已存在的類中的能力
??? 6.Annotation定義:定義Aspect使用的運行時Annotation(為JSR-175準備)
??? 7.XML定義:定義Aspect使用的XML;XML可以用來精煉、改寫和解析Annotation定義
??? 8.插件式Aspect管理器能夠和IoC框架(如Spring或PicoContainer)一起工作
??? 9.四種不同的Advice和Introduction部署模型(范圍):perJVM(單模式)、 perClass、perInstance 和perThread
??? 10.Advice和Introduction能夠動態部署、反部署或重新部署
??? 11.高性能,使用JIT編譯
??? 12.使用Fine-grained模式語言選擇join point
??? 13.所有Advice能夠和所有的join point和各種混合類型的pointcut
??? 14.脫機變換(可以用作后處理器)
??? 15.Aspect、Advice和Introduction使用POJO編碼
??? 16.目標類可以是正規的POJO,也就是不需要接口
??? 17.支持通過定義傳遞參數給Advice和定義可重用的Advice堆棧
??? 18.元數據被加到類中
??? 19.簡單的用法和配置
開始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)現在我要在輸出“Hello AOP!”前后做一些工作,這些工作在運行時會得到調用機會,如果使用AOP術語,我們可以說我們要編寫我們的aspect,這個aspect會在運行時被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)織入過程并不簡單,我們需要撰寫一個描述文件來將aspect和其織入的class中的信息聯系起來。
//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...