Advice通知
Advice(通知)定义在连接点做什么,为切面增强织入接口。在Spring AOP中,它主要描述Spring AOP
围绕方法调用而注入的切面行为。Advice是AOP联盟定义的一个接口,具体的接口定义在org.aopalliance.aop.
Advice中。在Spring AOP的实现中,使用了这个统一接口,并通过这个接口,为AOP切面增强的织入功能做了
更多的细化和扩展,比如提供了更具体的通知类型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等。作为
Spring AOP定义的接口类,具体的切面增强可以通过这些接口集成到AOP框架中去发挥作用。我们先从
BeforeAdvice开始。如下是Advice的类层级关系
在BeforeAdvice的继承关系中,定义了为待增强的目标方法设置的前置增强接口MethodBeforeAdvice,
如下
1 /** 2 * Advice invoked before a method is invoked. Such advices cannot 3 * prevent the method call proceeding, unless they throw a Throwable. 4 * 5 * @see AfterReturningAdvice 6 * @see ThrowsAdvice 7 * 8 * @author Rod Johnson 9 */ 10 public interface MethodBeforeAdvice extends BeforeAdvice { 11 12 /** 13 * Callback before a given method is invoked. 14 * @param method method being invoked 15 * @param args arguments to the method 16 * @param target target of the method invocation. May be {@code null}. 17 * @throws Throwable if this object wishes to abort the call. 18 * Any exception thrown will be returned to the caller if it's 19 * allowed by the method signature. Otherwise the exception 20 * will be wrapped as a runtime exception. 21 */ 22 void before(Method method, Object[] args, Object target) throws Throwable; 23 24 }
为了说明BeforeAdvice子类MethodBeforeAdvice的具体使用,来看一下子类CountingBeforeAdvice
1 public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice { 2 3 @Override 4 public void before(Method m, Object[] args, Object target) throws Throwable { 5 count(m); 6 } 7 8 }
这里调用了count方法,count方法在CountingBeforeAdvice的基类MethodCounter中实现
1 public class MethodCounter implements Serializable { 2 3 /** Method name --> count, does not understand overloading */ 4 private HashMap<String, Integer> map = new HashMap<String, Integer>(); 5 6 private int allCount; 7 8 protected void count(Method m) { 9 count(m.getName()); 10 } 11 12 protected void count(String methodName) { 13 Integer i = map.get(methodName); 14 i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1); 15 map.put(methodName, i); 16 ++allCount; 17 } 18 }
这个切面增强完成的统计实现并不复杂,它在对象中维护一个哈希表,用来存储统计数据
AfterAdvice
在Advice的实现体系中,Spring还提供了AfterAdvice这种通知类型,以AfterReturningAdvice通知的
实现为例,分析一下AfterAdvice通知类型的实现原理
1 public interface AfterReturningAdvice extends AfterAdvice { 2 3 /** 4 * Callback after a given method successfully returned. 5 * @param returnValue the value returned by the method, if any 6 * @param method method being invoked 7 * @param args arguments to the method 8 * @param target target of the method invocation. May be {@code null}. 9 * @throws Throwable if this object wishes to abort the call. 10 * Any exception thrown will be returned to the caller if it's 11 * allowed by the method signature. Otherwise the exception 12 * will be wrapped as a runtime exception. 13 */ 14 void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; 15 16 }
afterReturning方法也是一个回调函数,AOP应用需要在这个接口实现中提供切面增强的具体设计,在
这个Advice通知被正确配置以后,在目标方法调用结束并成功返回的时候,接口会被Spring AOP回调。
与前面分析BeforeAdvice一样,同样可以看到一个CountingAfterReturningAdvice,它的实现基本上与
CountingBeforeAdvice是一样的。
所不同的是调用发生的时间。尽管增强逻辑相同,但是,如果它实现不同的AOP通知接口,就会被AOP
编织到不同的调用场合中。尽管它们完成的增强行为是一样的,都是根据目标方法名对调用次数进行统计,
但是它们的最终实现却有很大的不同,一个是在目标方法调用前实现切面增强,一个在目标方法成功调用
返回结果后实现切面增强。由此可见,AOP技术给应用带来的灵活性,使得相同的代码完全可以根据应用
的需要灵活地出现在不同的应用场合。
ThrowsAdvice
了解了BeforeAdvice和AfterAdvice,在Spring AOP中,还有一种ThrowsAdvice,它在抛出异常是被回调
, 可以在CountingThrowsAdvice来了解ThrowsAdvice的使用方法,如下
1 @SuppressWarnings("serial") 2 public static class CountingThrowsAdvice extends MethodCounter implements ThrowsAdvice { 3 4 public void afterThrowing(IOException ex) throws Throwable { 5 count(IOException.class.getName()); 6 } 7 8 public void afterThrowing(UncheckedException ex) throws Throwable { 9 count(UncheckedException.class.getName()); 10 } 11 12 }
在afterThrowing中,从输入的异常对象中得到异常的名字并进行统计。