AspectJ是一個面向切面編程的框架,它擴展了Java語言。AspectJ定義了AOP語法所以它有一個專門的編譯器用來生成遵守Java字節編碼規範的Class文件。
AspectJ目前支持以下三種編織的方式
編譯時編織:把aspect類(aop的切面)和目標類(被aop的類)放在一起用ajc編譯。
後編譯時編織:目標類可能已經被打成了一個jar包,這時候也可以用ajc命令將jar再編織一次
加載時編織Load-time weaving (LTW):在jvm加載類的時候,做字節碼修改或替換
逆向工程中可以用到後兩個:後編譯時編織和加載時編織。
1.安裝AspectJ
下載地址:http://www.eclipse.org/aspectj/downloads.php
選擇裏面的1.9版本下載,下載完成之後是個jar包
安裝命令
java -jar aspectj-1.9.1.jar
根據提示設置好java主目錄和aspectj的安裝目錄,這裏採用默認的C:\aspectj1.9
安裝完成後,設置如下環境變量
設置ASPECTJ_HOME
ASPECTJ_HOME = C:\aspectj1.9
添加/修改CLASSPATH,把aspectjrt.jar添加進去
CLASSPATH = .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar;%ASPECTJ_HOME%\lib\aspectjrt.jar
PATH變量新增值
%ASPECTJ_HOME%\bin
環境變量設置完成之後,驗證命令
ajc -version
出現如下結果說明環境變量配置成功
2.看兩個簡單的例子
第一個項目helloworld
Java文件HelloWorld.java
//HelloWorld.java public class HelloWorld { public void sayHello() { System.out.println("Hello, world!"); } public static void main(String[] argv) { HelloWorld hw = new HelloWorld(); hw.sayHello(); } }
Aspectj文件MyAspect.aj
//MyAspect.aj public aspect MyAspect { pointcut say():call(void HelloWorld.sayHello()); before():say() { System.out.println("before say hello...."); } after():say() { System.out.println("after say hello...."); } }
Load-time weaving (LTW) 加載時編織命令
編譯
ajc -outjar myjar.jar HelloWorld.java ajc -outjar MyAspect.jar -outxml MyAspect.aj -classpath "myjar.jar;%CLASSPATH%"
運行
aj5 -classpath "MyAspect.jar;myjar.jar;%CLASSPATH%" HelloWorld
運行結果
可以看到在helloworld字符串上有上下兩行文字
第二個項目,輸出參數和返回值
java文件Main.java
//Main.java package com.vvvtimes; public class Main { public int add(int x, int y) { return x + y; } public int add(int x, int y, int z) { return x + y + z; } public static void main(String[] args) { Main m = new Main(); System.out.println(m.add(1, 2)); System.out.println(m.add(1, 2, 3)); } }
Aspectj文件Tracing.aj
//Tracing.aj public aspect Tracing { private pointcut mainMethod(): execution(public static void main(String[])); before(): mainMethod() { System.out.println("> " + thisJoinPoint); } after(): mainMethod() { System.out.println("< " + thisJoinPoint); } private pointcut addMethod(): execution(public int add(..)); before(): addMethod() { System.out.println("> " + thisJoinPoint); Object[] args = thisJoinPoint.getArgs(); for (int i = 0; i < args.length; i++) { System.out.println("args[" + i + "]: " + thisJoinPoint.getArgs()[i].toString()); } } after(): addMethod() { System.out.println("< " + thisJoinPoint); } after() returning(Object o) :addMethod(){ System.out.println("Return value: " + o.toString()); } }
編譯
ajc -outjar myjar.jar com/vvvtimes/Main.java ajc -outjar Tracing.jar -outxml Tracing.aj -classpath "myjar.jar;%CLASSPATH%"
運行
aj5 -classpath "Tracing.jar;myjar.jar;%CLASSPATH%" com.vvvtimes.Main
運行結果
可以看到,add方法的參數和返回值都打印出來了
順便說一下三個編織期的區別,從命令行角度比較如下:
Compile-time weaving 編譯時編織
ajc -outjar mytarget.jar HelloWorld.java MyAspect.aj
運行
aj5 -classpath "mytarget.jar;%CLASSPATH%" HelloWorld
Post-compile weaving 後編譯時編織
ajc -outjar myjar.jar HelloWorld.java ajc -inpath myjar.jar MyAspect.aj -outjar mytarget.jar
運行
aj5 -classpath "mytarget.jar;%CLASSPATH%" HelloWorld
Load-time weaving (LTW) 加載時編織
編譯
ajc -outjar myjar.jar HelloWorld.java ajc -outjar MyAspect.jar -outxml MyAspect.aj -classpath "myjar.jar;%CLASSPATH%"
運行
aj5 -classpath "MyAspect.jar;myjar.jar;%CLASSPATH%" HelloWorld