Aspectj LTW 实践

Aspectj LTW 实践

Aspectj LTW 实践

本文将介绍使用 AspectJ,介绍它的 3 种织入方式。

AspectJ 作为 AOP 编程的完全解决方案,提供了三种织入时机,分别为

  1. compile-time:编译期织入,在编译的时候一步到位,直接编译出包含织入代码的 .class 文件
  2. post-compile:编译后织入,增强已经编译出来的类,如我们要增强依赖的 jar 包中的某个类的某个方法
  3. load-time:在 JVM 进行类加载的时候进行织入

通过一个简单的应用程序,来说明Aspectj LTW 的简单实践

1.新建被织入的类 Simple.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Simple {
public static void main(String[]argv) {
countFast(1000);
countSlow(1000);
}

public static void countSlow(int value) {
count(value,5);
}

public static void countFast(int value) {
count(value,0);
}

private static void count(int value, int delay) {
for (int i=0;i<value;i++) {
try {Thread.sleep(delay);} catch (Exception e) {}
}
}
}

2.aspectj 织入类WhereDoesTheTimeGo.aj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
aspect WhereDoesTheTimeGo {

pointcut methodsOfInterest(): execution(* *(..)) &&
!within(WhereDoesTheTimeGo);

private int nesting = 0;

Object around(): methodsOfInterest() {
nesting++;
long stime=System.currentTimeMillis();
Object o = proceed();
long etime=System.currentTimeMillis();
nesting--;
StringBuilder info = new StringBuilder();
for (int i=0;i<nesting;i++) {
info.append(" ");
}
info.append(thisJoinPoint+" took "+(etime-stime)+"ms");
System.out.println(info.toString());
return o;
}
}

编译时织入

1
2
3
4
5
6
7
8
ajc WhereDoesTheTimeGo.aj Simple.java
java Simple
//输出
execution(void Simple.count(int, int)) took 2ms
execution(void Simple.countFast(int)) took 4ms
execution(void Simple.count(int, int)) took 5049ms
execution(void Simple.countSlow(int)) took 5049ms
execution(void Simple.main(String[])) took 5054ms

运行时织入

首先清理 文件夹内所有编译好的class

这时候只编译 Simple.java 生成Simple.class

1
javac Simple.java

这个Simple.class 只是简简单单的编译后class文件

通过aj编译期,将 WhereDoesTheTimeGo.aj 编译为 jar包

1
ajc WhereDoesTheTimeGo.aj -outxml -outjar timing.jar

这个timing.jar 就是我们要织入的jar包,通过aj编辑器后,内部结构是这样的:

1
2
3
4
jar -tvf timing.jar
55 Wed Feb 25 22:06:30 GMT 2009 META-INF/MANIFEST.MF
5149 Wed Feb 25 22:06:32 GMT 2009 WhereDoesTheTimeGo.class
85 Wed Feb 25 22:06:32 GMT 2009 META-INF/aop-ajc.xml

验证:

执行

1
2
java Simple
//没有任何输出

配置-javaagent

1
2
3
4
5
6
7
8
java -javaagent:<pathToAspectj>/lib/aspectjweaver.jar
-classpath "code;timing.jar;<pathToAspectj>/lib/aspectjrt.jar" Simple
//输出
execution(void Simple.count(int, int)) took 1ms
execution(void Simple.countFast(int)) took 6ms
execution(void Simple.count(int, int)) took 5114ms
execution(void Simple.countSlow(int)) took 5114ms
execution(void Simple.main(String[])) took 5121ms

注意:在linux 系统,classpath 的分隔符要改为 :

配置aop-ajc.xml

我们在生成织入jar时,是有aj编译期自动生成了默认的ajc配置文件,其内容是:

1
2
3
4
5
<aspectj> 
<aspects>
<aspect name = WhereDoesTheTimeGo” />
</ aspects>
</ aspectj>

我们可以指定aspectj 的配置文件,方式有两个

  1. 方式一是在目录下,新建META-INF目录,在该目录下aop-ajc.xml,aj打包时将自动选择xml文件作为aspectj的配置文件
  2. 方式二是,使用 -outxmlfile .xml 指定特定目录的xml文件作为aspectj的配置文件

我们简单修改ajc配置文件,增加weaver节点,以实现打印织入详情

1
2
3
4
5
6
<aspectj> 
<aspects>
<aspect name = WhereDoesTheTimeGo” />
</ aspects>
<weaver options =“-verbose -showWeaveInfo” />
</aspectj>

这时候重新生成timing.jar ,再次执行,这时候输出的内容就多得多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
java -javaagent:<pathToAspectj>/lib/aspectjweaver.jar
-classpath "code;timing.jar;<pathToAspectj>/lib/aspectjrt.jar" Simple
//输出
[AppClassLoader@9fbe93] info AspectJ Weaver Version DEVELOPMENT
built on Wednesday Feb 25, 2009 at 21:17:03 GMT
[AppClassLoader@9fbe93] info register classloader sun.misc.Launcher$AppClassLoader@9fbe93
[AppClassLoader@9fbe93] info using configuration
file:/C:/blog/timing.jar!/META-INF/aop-ajc.xml
[AppClassLoader@9fbe93] info register aspect WhereDoesTheTimeGo
[AppClassLoader@9fbe93] weaveinfo Join point
'method-execution(void Simple.main(java.lang.String[]))'
in Type 'Simple' (Simple.java:3) advised by around advice
from 'WhereDoesTheTimeGo' (WhereDoesTheTimeGo.java:7)
[AppClassLoader@9fbe93] weaveinfo Join point
'method-execution(void Simple.countSlow(int))'
in Type 'Simple' (Simple.java:8) advised by around advice
from 'WhereDoesTheTimeGo' (WhereDoesTheTimeGo.java:7)
[AppClassLoader@9fbe93] weaveinfo Join point
'method-execution(void Simple.countFast(int))'
in Type 'Simple' (Simple.java:12) advised by around advice
from 'WhereDoesTheTimeGo' (WhereDoesTheTimeGo.java:7)
[AppClassLoader@9fbe93] weaveinfo Join point
'method-execution(void Simple.count(int, int))'
in Type 'Simple' (Simple.java:16) advised by around advice
from 'WhereDoesTheTimeGo' (WhereDoesTheTimeGo.java:7)
[AppClassLoader@9fbe93] info processing reweavable type WhereDoesTheTimeGo:
WhereDoesTheTimeGo.java
execution(void Simple.count(int, int)) took 1ms
execution(void Simple.countFast(int)) took 3ms
execution(void Simple.count(int, int)) took 5005ms
execution(void Simple.countSlow(int)) took 5005ms
execution(void Simple.main(String[])) took 5016ms

也可以开启 -debug 模式

1
2
3
4
5
6
7
8
<aspectj>
<aspects>
<aspect name="WhereDoesTheTimeGo"/>
</aspects>
<weaver options="-debug">
<exclude within="Simple">
</weaver>
</aspectj>

通过这3个选项,我可以研究在尝试进行加载时编织时看到的任何基本问题。甚至更高级的选项可能涉及打开weaver跟踪或转储字节码(在编织之前和之后),但是当AspectJ编译器开发人员要求进行诊断时,通常会使用这些选项。


 
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×