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