</p> 各种通知类型包括:2 ]# r, [, R0 Y3 u1 s# q$ T
— Around通知:包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为,它们负责选择继续执行连接点或通过返回它们自己的返回值或抛出异常来短路执行。
- v4 Y) K- _# M% ]+ g; h — Before通知:在一个连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
3 \3 ]2 i; Q, w5 [, L — Throws通知:在方法抛出异常时执行的通知。Spring提供强制类型的Throws通知,因此你可以书写代码捕获感兴趣的异常(和它的子类),不需要从Throwable或Exception强制类型转换。
B& M& U! L9 J2 f! _. V" D — After returning通知:在连接点正常完成后执行的通知,例如,一个方法正常返回,没有抛出异常。2 H0 P8 q" D" \- H2 J1 q4 x+ ]% O
Around通知是最通用的通知类型。大部分基于拦截的AOP框架(如Nanning和Jboss 4)只提供Around通知。2 ^0 D6 U. M+ d) K- c- Y' `
如同AspectJ,Spring提供所有类型的通知,我们推荐你使用最为合适的通知类型来实现需要的行为。例如,如果只是需要用一个方法的返回值来更新缓存,你最好实现一个after returning通知,而不是around通知,虽然around通知也能完成同样的事情。使用最合适的通知类型使编程模型变得简单,并能减少潜在错误。例如,你不需要调用在around通知中所需使用的MethodInvocation的proceed()方法,因此就调用失败。
3 U o! P r7 i 切入点的概念是AOP的关键,它使AOP区别于其他使用拦截的技术。切入点使通知独立于OO的层次选定目标。例如,提供声明式事务管理的around通知可以被应用到跨越多个对象的一组方法上。 因此切入点构成了AOP的结构要素。% e/ c6 t, r8 k* c/ I
下面让我们实现一个Spring AOP的例子。在这个例子中,我们将实现一个before advice,这意味着advice的代码在被调用的public方法开始前被执行。以下是这个before advice的实现代码。
) i F5 S/ I- j" p package com.ascenttech.springaop.test;
! ^8 a) b! C5 M import java.lang.reflect.Method;2 X# o# R) ]4 u
import org.springframework.aop.MethodBeforeAdvice;
/ g% O3 h( Z% O public class TestBeforeAdvice implements MethodBeforeAdvice {# }! M7 r4 Z1 N5 o, q2 t# C
public void before(Method m, Object[] args, Object target)6 @' D9 h$ P* v x Z5 N9 r% w" P
throws Throwable {
C" [0 c5 k/ H/ n System.out.println("Hello world! (by "$ O" x5 N" \3 \- L) Q
+ this.getClass().getName()
+ `5 O* Y: j* i; g. M + ")");
4 Q% S: M' x/ k0 z2 R0 k }
$ h6 R" f/ U: K6 `1 j( a/ j1 V/ v }1 o+ A: ~) h. ]
接口MethodBeforeAdvice只有一个方法before需要实现,它定义了advice的实现。before方法共用3个参数,它们提供了相当丰富的信息。参数Method m是advice开始后执行的方法,方法名称可以用作判断是否执行代码的条件。Object[] args是传给被调用的public方法的参数数组。当需要记日志时,参数args和被执行方法的名称都是非常有用的信息。你也可以改变传给m的参数,但要小心使用这个功能;编写最初主程序的程序员并不知道主程序可能会和传入参数的发生冲突。Object target是执行方法m对象的引用。0 ^4 D9 y/ K9 |0 ~# F! b
在下面的BeanImpl类中,每个public方法调用前,都会执行advice,代码如下。
: Y) x$ r; u# Z" q: o package com.ascenttech.springaop.test;
& U* b6 m# Q* o7 H public class BeanImpl implements Bean {' j; A E1 Z9 V
public void theMethod() {
1 L" _& K# d* J: n3 L7 }# J) x System.out.println(this.getClass().getName()2 R& q5 O0 u8 P! a
+ "." + new Exception().getStackTrace()[0].getMethodName()
% u3 H, |, A: X2 N! H! T + "()"
+ p2 t' h! m6 z" r + " says HELLO!");6 R& H; p& D9 ^5 Q" N
}
[. L& x8 {" _8 b }) u1 F, c. d( A- L, U6 n
类BeanImpl实现了下面的接口Bean,代码如下。
$ m' Q' q# ]. W package com.ascenttech.springaop.test;
' A+ J, ?6 j7 ]& \! d public interface Bean {
2 l9 O0 ]: l+ Q6 f; N% F" E& g" Z public void theMethod();- i, k7 L' r" a1 {2 k: j
1 U$ h& j8 H5 y5 G( I } |