Spring-AOP、Struts2拦截器、MyBatis Plugin实现原理比较(三)
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 { ....... } }