Spring AOP
Spring和struts2拦截链的实现理念是一样的,所有的拦截器会组织成一个链,由中央调度器统一推进。
Spring在拦截器(通知 Advice) 的接口上做得更细致一些,在MyBatis和Struts2中,拦截器链的推进是要在每个拦截器的实现中显式调用的。而在Spring中,这个动作已经被封装了。
看下面这个 AfterReturningAdvice 通知
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
你只要实现一个afterReturning方法,就可以在拦截点执行后,执行这个方法。按逻辑说,需要在这个方法执行之前,推进拦截链的执行,待其返回后再执行这个方法。 这个拦截链推进在什么地方呢?
其实这里的Advice并不能直接够成拦截器,AfterReturningAdvice会被Spring-AOP包装成下面的AfterReturningAdviceInterceptor。 在AfterReturningAdviceInterceptor中,我们看到到了熟悉的invoke,它的参数MethodInvocation 就是中央调度器,和Struts2一样,它里面封装了整个拦截链。
AfterReturningAdviceInterceptor 内部封装了 AfterReturningAdvice,在invoke调用时,先是推进了拦截链前进,保存返回值,再调用afterReturning 方法来完成切面逻辑。
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
下面就是推进拦截链的方法proceed(),推进原理和Struts2是一样的
从interceptorsAndDynamicMethodMatchers中取出下一个拦截器,如果是动态拦截器,则匹配后再执行;否则直接调用拦截器的invoke
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
如果currentInterceptorIndex已经是最后一个索引,就直接执行拦截点的方法
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
下面这个invoke是对目标拦截对象的代理拦截入口
这里面初始化了ReflectiveMethodInvocation 这个中央调度器的实例,拦截链chain也做为参数传了进去。
最后通过 invocation.proceed(); 启动这个拦截链,开始了层层拦截。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.edvised.targetSource;
Class targetClass = null;
Object target = null;
try {
.......
if (chain.isEmpty()) {
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
.......
return retVal;
}
finally {
.......
}
}