本文不打算解释AOP的相关专业名词和概念,仅通过几个代码示例来展示Aspectj(对AOP实现的)的基本使用,并且使用的Aspectj是目前最新版本。
1.搭建环境
本文使用Maven来构建工程,通过aspectj-maven-plugin插件来编译*.aj文件至.class。
Maven的具体配置:
1
2
3
4
5
6
7
8
|
< plugin >
< groupId >org.codehaus.mojo</ groupId >
< artifactId >aspectj-maven-plugin</ artifactId >
< version >1.7</ version >
< configuration >
< complianceLevel >1.6</ complianceLevel >
</ configuration >
</ plugin >
|
在上面的configuration节点下可以配置
1
|
< aspectDirectory ></ aspectDirectory >
|
默认是src/main/aspect , 可以根据需要进行设置。
配置aspectj运行时环境依赖jar
1
2
3
4
5
|
< dependency >
< groupId >org.aspectj</ groupId >
< artifactId >aspectjrt</ artifactId >
< version >1.8.2</ version >
</ dependency >
|
2.创建一个普通的Java类(Simple.java),为接下来使用Aspectj来植入相应功能做准备
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
|
package com.rft.fdsi.server.aop;
public class Simple {
static {
System.out.println( "[src] static init" );
}
public Simple() {
System.out.println( "[src] construct" );
}
public String welcome(String name) {
System.out.println( "[src]===========start===========" );
System.out.println( "[src] welcome method execute" );
System.out.println( "[src] welcome method execute" );
System.out.println( "[src]===========end===========" );
// throw new RuntimeException("runtime exception");
return "welcome " + name;
}
public static void main(String[] args) {
Simple simple = new Simple();
String greeting = simple.welcome( "Jack" );
System.out.println(greeting);
}
} |
3.创建一个针对Simple类的静态代码块初始化,构造方法执行,方法调用进行植入功能的方面类(SimpleAspect.aj)。
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package com.rft.fdsi.server.aop;
public aspect SimpleAspect {
public pointcut staticInit() : staticinitialization(com.rft.fdsi.server.aop.Simple);
before() : staticInit() {
System.out.println( "[before]"
+ thisJoinPointStaticPart.getSignature().getName());
}
after() returning() : staticInit() {
System.out.println( "[after returning]"
+ thisJoinPointStaticPart.getSignature().getName());
}
before() : call( public com.rft.fdsi.server.aop.*. new ()) {
System.out.println( "[before]" + thisJoinPoint.getSignature().getName());
}
after() : call( public com.rft.fdsi.server.aop.*. new ()) {
System.out.println( "[after]" + thisJoinPoint.getSignature().getName());
}
public pointcut welcomeMethod(String name) : call( public String com.rft.fdsi.server..*.welcome(String)) && args(name);
before(String name): welcomeMethod(name){
System.out
.println( "[before]"
+ thisJoinPoint.getTarget().getClass()
.getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName()
+ " args_name=" + name);
}
after(String name) returning(String retval) : welcomeMethod(name) {
System.out.println( "[after returning]"
+ thisJoinPoint.getTarget().getClass().getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName() + " args_name=" + name
+ " return_value =" + retval);
}
after(String name) : welcomeMethod(name){
System.out
.println( "[after]"
+ thisJoinPoint.getTarget().getClass()
.getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName()
+ " args_name=" + name);
}
after(String name) throwing(java.lang.Exception e) : welcomeMethod(name)
{
System.out.println( "[after throwing]"
+ thisJoinPoint.getTarget().getClass().getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName() + " throwing="
+ e.getMessage());
}
} |
上面显示的声明了两个切入点(Pointcut)分别是:staticInit()(该切入点的连接点是Simple类的静态代码块), welcomeMethod(name)(该切入点的连接点是Simple对象的welcomeMethod方法);隐式的在前置通知和后置通知中声明了相同的切入点,该切入点的连接是Simple的构造方法。
上面使用到了Aspectj内置的5中通知类型的四种:before(连接点执行前通知)after returning(连接点正常完成后通知),after throwing(连接点执行中发生异常后通知),after(连接点完成后通知,无论正常还是异常)。另外一种是around(环绕通知,在连接点执行前,执行完成后都通知)。
使用aspectj-maven-pugin来编译SimpleAspect.aj文件,执行命令:mvn aspectj:compile 即可。
4.测试效果
1
2
3
4
5
|
public static void main(String[] args) {
Simple simple = new Simple();
String greeting = simple.welcome( "Jack" );
System.out.println(greeting);
}
|
如果没有Aspject的植入的话,上面输入的结果应该是Simple中的输入内容加上"welcome Jack",现在执行的结果如下图所示:
after throwing通知没有执行,去掉Simple类中welcome方法中的异常抛出注释,并且注释掉返回值,执行测试,将可以看到after throwing在连接点welcome执行发送异常后执行通知。
5.添加around通知在SimpleAspect.aj方面类中,另外需要注释掉其中welcomeMethod切入点表达式上的after和before通知,因为同时指定before,after,around将无发确定其执行的顺序,而且指定around通知后没必要存在before,after通知,around通知是可以实现这两种通知的效果的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
String around(String name) : welcomeMethod(name){ System.out.println( "[around]========start=========" );
System.out
.println( "[around]"
+ thisJoinPoint.getTarget().getClass()
.getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName()
+ " args_name=" + name);
String retval = proceed(name);
System.out.println( "[around]"
+ thisJoinPoint.getTarget().getClass().getCanonicalName() + "."
+ thisJoinPoint.getSignature().getName() + " args_name=" + name
+ " return_value=" + retval);
System.out.println( "[around] modify return value append '!!!' = "
+ (retval = retval + "!!!" ));
System.out.println( "[around]========end=========" );
return retval;
}
|
执行测试后可以看到下图,around通知在连接点welcome方法出执行,其在连接点执行前打印输出内容,在连接点执行完成后获取到返回值,并加以修改后返回。around通知在五中通知类型中最为强大,实际应用中则根据要植入的功能情况加以选择即可。
本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1639440,如需转载请自行联系原作者