引
接前面一章继续分析SpringAOP获取拦截器链和拦截器链的调用过程。
1.获取拦截器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
/** * 获取拦截器链 */ @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. // 获取AdvisorAdapterRegistry对象,Spring默认初始化了MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter和ThrowsAdviceAdapter AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); // 获取所有增强 Advisor[] advisors = config.getAdvisors(); // 创建interceptorList保存返回结果,这里可以看到new ArrayList指定了集合长度,也是编码中节约内存开销的一个小技巧 List<Object> interceptorList = new ArrayList<>(advisors.length); // 获取代理类的Class对象 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); Boolean hasIntroductions = null; // 循环所有的增强 for (Advisor advisor : advisors) { // 如果增强是PointcutAdvisor的实例 if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; // config.isPreFiltered() -> 返回是否对该代理配置进行了预筛选,以便仅对其进行筛选包含适用的增强(匹配此代理的目标类)。 // pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) -> 当前切点匹配的类是否匹配actualClass // 以上两个条件是在类一级别上做出判断,如果符合,则接下来对方法级别的再做匹配判断 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 获取当前切点匹配的方法 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; // 区分普通的MethodMatcher和IntroductionAwareMethodMatcher,分别调用不同的匹配方法做出判断 // IntroductionAwareMethodMatcher可以作用域引入类型的增强,且当匹配方法不包含引用增强时,可以提升匹配效率 if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } // 如果匹配 if (match) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } // 如果增强是IntroductionAdvisor实例 else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } // 其他类型 else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
该段代码比较关键的点:
// 如果匹配,获取方法拦截器 if (match) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } }
通过上面的代码可以发现Spring最终还是要把增强(切面)转换为方法拦截器,来看其具体的实现:
/** * 获取方法连接器 */ @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); // 1.如果增强是MethodInterceptor类型直接添加 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } // 2.循环增强适配器,并判断是否支持 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } // 3.返回结果 return interceptors.toArray(new MethodInterceptor[0]); }
通过这段代码,如果增强是MethodInterceptor的实例,直接加入结果中;那么哪些增强是MethodInterceptor类型呢?先不用着急,继续看下面的处理,下面的代码里出现了一个增强适配器,我们来看一下其中都包含了哪些适配器类型:
private final List<AdvisorAdapter> adapters = new ArrayList<>(3); public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); }
DefaultAdvisorAdapterRegistry通过构造函数对增强适配器进行了初始化,包含了MethodBeforeAdviceAdapter前置增强适配器、AfterReturningAdviceAdapter后置返回增强适配器、ThrowsAdviceAdapter后置异常增强适配器。那么从这里我们也可以推断出,除了这几种增强适配器对应的增强类型之外,其他的都是MethodInterceptor类型。
接下来看下这三种适配器都做了哪些工作:
- MethodBeforeAdviceAdapter
/** * 增强适配器 * 这个方法在获取拦截器链的时候调用,从这里也可以看出,Spring中的advisor(增强/切面) * 最终还是被转换为MethodInterceptor对象 * * AdvisorAdapter的实现类有AfterReturningAdviceAdapter,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter三个 * * AfterReturningAdviceAdapter -> new AfterReturningAdviceInterceptor(advice) -> 后置返回增强 * MethodBeforeAdviceAdapter -> new MethodBeforeAdviceInterceptor(advice) -> 前置增强 * ThrowsAdviceAdapter -> new ThrowsAdviceInterceptor(advisor.getAdvice()) -> 该适配器有些特殊...看源码吧 */ @Override public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); }
- AfterReturningAdviceAdapter
public MethodInterceptor getInterceptor(Advisor advisor) { AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice(); return new AfterReturningAdviceInterceptor(advice); }
- ThrowsAdviceAdapter
@Override public MethodInterceptor getInterceptor(Advisor advisor) { return new ThrowsAdviceInterceptor(advisor.getAdvice()); }
看到这里大家一定有所了解了,Spring中的增强,最终还是会转换为方法拦截器调用。
3. 拦截器链调动过程
/** * 调用拦截器链 * * currentInterceptorIndex维护了一个计数器,该计数器从-1开始,当计数器值等于拦截方法长度减一时, * 表名所有的增强方法已经被调用(但是不一定被真正执行),那么此时调用连接点的方法,针对本例:即sayHello方法 */ @Override @Nullable 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; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); // 匹配成功则执行 if (dm.methodMatcher.matches(this.method, 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. // System.out.println(interceptorOrInterceptionAdvice.getClass()); return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
这段代码看似简单,但是如果真的debug进去,方法栈还是比较深刻的,前面介绍过在获取到合适的增强集合之后,首先在其首位加入了ExposeInvocationInterceptor拦截器,然后对增强集合进行了排序(当然ExposeInvocationInterceptor依然会在首位),那么接下来第一个拦截器调用就是ExposeInvocationInterceptor了。
- ExposeInvocationInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); invocation.set(mi); try { // 继续拦截器链调用 return mi.proceed(); } finally { invocation.set(oldInvocation); } }
- AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { // 继续拦截器链调用 return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
- AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { // 继续拦截器链调用 return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
- AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { // 继续拦截器链调用 Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
- AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { // 继续拦截器链调用 return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } }
- AspectJAroundAdvice
public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); }
在这里终于看到了方法的调用:
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (this.aspectJAdviceMethod.getParameterCount() == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(this.aspectJAdviceMethod); // TODO AopUtils.invokeJoinpointUsingReflection // 调用代理方法 return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); } catch (IllegalArgumentException ex) { throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex); } catch (InvocationTargetException ex) { throw ex.getTargetException(); }
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
代码终于执行到了Method类的invoke方法,接下来就可以调用我们的增强方法了:
- MethodBeforeAdviceInterceptor
@Around("test()") public Object aroundTest(ProceedingJoinPoint p) throws Throwable { System.out.println("==环绕增强开始"); // 继续拦截器链调用 Object o = p.proceed(); System.out.println("==环绕增强结束"); return o; }
执行完之后,我们发现前置增强还没有被调用进来,继续:
public Object invoke(MethodInvocation mi) throws Throwable { // 调用前置增强 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); }
- 目标方法
执行完前置增强之后,再次进入到proceed方法,这时候,计数器已经满足条件了,执行目标方法调用:
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); }
待执行完目标方法调用后,再将之前压入方法栈的那些增强方法依次出栈并调用。这一段的代码调用用文字表述挺困难的,大家自己跟踪代码吧。。。
到这里拦截器链的调用过程分析就结束了,这里分析的不是那么明确,还是多跟踪代码吧。