天天看点

Aspectj快速上手代码示例之Before,After,Around

 本文不打算解释AOP的相关专业名词和概念,仅通过几个代码示例来展示Aspectj(对AOP实现的)的基本使用,并且使用的Aspectj是目前最新版本。

 1.搭建环境

  本文使用Maven来构建工程,通过aspectj-maven-plugin插件来编译*.aj文件至.class。

  Maven的具体配置:

1

2

3

4

5

6

7

8

<code>&lt;</code><code>plugin</code><code>&gt;</code>

<code>                </code><code>&lt;</code><code>groupId</code><code>&gt;org.codehaus.mojo&lt;/</code><code>groupId</code><code>&gt;</code>

<code>                </code><code>&lt;</code><code>artifactId</code><code>&gt;aspectj-maven-plugin&lt;/</code><code>artifactId</code><code>&gt;</code>

<code>                </code><code>&lt;</code><code>version</code><code>&gt;1.7&lt;/</code><code>version</code><code>&gt;</code>

<code>                </code><code>&lt;</code><code>configuration</code><code>&gt;</code>

<code>                    </code><code>&lt;</code><code>complianceLevel</code><code>&gt;1.6&lt;/</code><code>complianceLevel</code><code>&gt;</code>

<code>                </code><code>&lt;/</code><code>configuration</code><code>&gt;</code>

<code>            </code><code>&lt;/</code><code>plugin</code><code>&gt;</code>

  在上面的configuration节点下可以配置

<code>&lt;</code><code>aspectDirectory</code><code>&gt;&lt;/</code><code>aspectDirectory</code><code>&gt;</code>

 默认是src/main/aspect , 可以根据需要进行设置。

 配置aspectj运行时环境依赖jar

<code>&lt;</code><code>dependency</code><code>&gt;</code>

<code>            </code><code>&lt;</code><code>groupId</code><code>&gt;org.aspectj&lt;/</code><code>groupId</code><code>&gt;</code>

<code>            </code><code>&lt;</code><code>artifactId</code><code>&gt;aspectjrt&lt;/</code><code>artifactId</code><code>&gt;</code>

<code>            </code><code>&lt;</code><code>version</code><code>&gt;1.8.2&lt;/</code><code>version</code><code>&gt;</code>

<code>        </code><code>&lt;/</code><code>dependency</code><code>&gt;</code>

 2.创建一个普通的Java类(Simple.java),为接下来使用Aspectj来植入相应功能做准备

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<code>package</code> <code>com.rft.fdsi.server.aop;</code>

<code>public</code> <code>class</code> <code>Simple {</code>

<code>    </code><code>static</code> <code>{</code>

<code>        </code><code>System.out.println(</code><code>"[src] static init"</code><code>);</code>

<code>    </code><code>}</code>

<code>    </code><code>public</code> <code>Simple() {</code>

<code>        </code><code>System.out.println(</code><code>"[src] construct"</code><code>);</code>

<code>    </code><code>public</code> <code>String welcome(String name) {</code>

<code>        </code><code>System.out.println(</code><code>"[src]===========start==========="</code><code>);</code>

<code>        </code><code>System.out.println(</code><code>"[src] welcome method execute"</code><code>);</code>

<code>        </code><code>System.out.println(</code><code>"[src]===========end==========="</code><code>);</code>

<code>        </code><code>// throw new RuntimeException("runtime exception");</code>

<code>        </code><code>return</code> <code>"welcome "</code> <code>+ name;</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>

<code>        </code><code>Simple simple = </code><code>new</code> <code>Simple();</code>

<code>        </code><code>String greeting = simple.welcome(</code><code>"Jack"</code><code>);</code>

<code>        </code><code>System.out.println(greeting);</code>

<code>}</code>

 3.创建一个针对Simple类的静态代码块初始化,构造方法执行,方法调用进行植入功能的方面类(SimpleAspect.aj)。

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

<code>public</code> <code>aspect SimpleAspect {</code>

<code>    </code><code>public</code> <code>pointcut staticInit() : staticinitialization(com.rft.fdsi.server.aop.Simple);</code>

<code>    </code><code>before() : staticInit() {</code>

<code>        </code><code>System.out.println(</code><code>"[before]"</code>

<code>                </code><code>+ thisJoinPointStaticPart.getSignature().getName());</code>

<code>    </code><code>after() returning() : staticInit() {</code>

<code>        </code><code>System.out.println(</code><code>"[after returning]"</code>

<code>    </code><code>before() : call(</code><code>public</code> <code>com.rft.fdsi.server.aop.*.</code><code>new</code><code>()) {</code>

<code>        </code><code>System.out.println(</code><code>"[before]"</code> <code>+ thisJoinPoint.getSignature().getName());</code>

<code>    </code><code>after() : call(</code><code>public</code> <code>com.rft.fdsi.server.aop.*.</code><code>new</code><code>()) {</code>

<code>        </code><code>System.out.println(</code><code>"[after]"</code> <code>+ thisJoinPoint.getSignature().getName());</code>

<code>    </code><code>public</code> <code>pointcut welcomeMethod(String name) : call(</code><code>public</code> <code>String com.rft.fdsi.server..*.welcome(String)) &amp;&amp; args(name);</code>

<code>    </code><code>before(String name): welcomeMethod(name){</code>

<code>        </code><code>System.out</code>

<code>                </code><code>.println(</code><code>"[before]"</code>

<code>                        </code><code>+ thisJoinPoint.getTarget().getClass()</code>

<code>                                </code><code>.getCanonicalName() + </code><code>"."</code>

<code>                        </code><code>+ thisJoinPoint.getSignature().getName()</code>

<code>                        </code><code>+ </code><code>" args_name="</code> <code>+ name);</code>

<code>    </code><code>after(String name) returning(String retval) : welcomeMethod(name) {</code>

<code>                </code><code>+ thisJoinPoint.getTarget().getClass().getCanonicalName() + </code><code>"."</code>

<code>                </code><code>+ thisJoinPoint.getSignature().getName() + </code><code>" args_name="</code> <code>+ name</code>

<code>                </code><code>+ </code><code>" return_value ="</code> <code>+ retval);</code>

<code>    </code><code>after(String name) : welcomeMethod(name){</code>

<code>                </code><code>.println(</code><code>"[after]"</code>

<code>    </code><code>after(String name) throwing(java.lang.Exception e) : welcomeMethod(name)</code>

<code>     </code><code>{</code>

<code>        </code><code>System.out.println(</code><code>"[after throwing]"</code>

<code>                </code><code>+ thisJoinPoint.getSignature().getName() + </code><code>" throwing="</code>

<code>                </code><code>+ e.getMessage());</code>

  上面显示的声明了两个切入点(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.测试效果

<code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>

 如果没有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通知是可以实现这两种通知的效果的。

<code>String around(String name) : welcomeMethod(name){</code>

<code>        </code><code>System.out.println(</code><code>"[around]========start========="</code><code>);</code>

<code>                </code><code>.println(</code><code>"[around]"</code>

<code>        </code><code>String retval = proceed(name);</code>

<code>        </code><code>System.out.println(</code><code>"[around]"</code>

<code>                </code><code>+ </code><code>" return_value="</code> <code>+ retval);</code>

<code>        </code><code>System.out.println(</code><code>"[around] modify return value append '!!!' = "</code>

<code>                </code><code>+ (retval = retval + </code><code>"!!!"</code><code>));</code>

<code>        </code><code>System.out.println(</code><code>"[around]========end========="</code><code>);</code>

<code>        </code><code>return</code> <code>retval;</code>

执行测试后可以看到下图,around通知在连接点welcome方法出执行,其在连接点执行前打印输出内容,在连接点执行完成后获取到返回值,并加以修改后返回。around通知在五中通知类型中最为强大,实际应用中则根据要植入的功能情况加以选择即可。

<a href="http://s3.51cto.com/wyfs02/M00/6C/08/wKioL1U-ML7wX0ksAAM76I7FzXg085.jpg" target="_blank"></a>

本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1639440,如需转载请自行联系原作者