本系列文章的上一篇 : Spring MVC : 控制器方法处理请求的过程分析 - 4. 控制器方法参数值的验证 MethodValidationInterceptor
实际上,在本系列上一篇讲解控制器方法参数值的验证时,我们已经讲解了目标控制方法自身被调用的过程,依旧是如下代码所示 :
// InvocableHandlerMethod 代码片段
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 此处逻辑是本系列以上几篇文章所介绍的请求参数值解析和绑定的逻辑,
// 当此方法返回时,args 中的对象已经按照目标方法参数列表的结构(顺序,类型)
// 组织好可以直接应用了
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 现在使用 args 继续发起对目标控制器方法的调用,并返回其返回值
return doInvoke(args);
}
其中InvocableHandlerMethod#doInvoke
实现如下 :
@Nullable
protected Object doInvoke(Object... args) throws Exception {
// 确保目标控制器方法是可以访问的
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// 调用目标控制器方法
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
// 抛出参数格式错误导致的异常
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
// 对 InvocationTargetException 异常的处理
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
从这里不难看出,#doInvoke
方法确实是对目标控制器方法发起了调用。但由于Spring AOP
机制的作用,#getBean
方法返回的有可能是目标控制器bean
对象的代理对象。上述getBridgedMethod().invoke(getBean(), args)
调用会先触发层层方法拦截器,没有拦截逻辑异常或者其他分支的情况下,目标控制器方法会被最终调用。这段逻辑我们可以参考 :
// ReflectiveMethodInvocation 代码片段
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// this.currentInterceptorIndex 总是指向下一个将要执行的拦截器,初始值为 -1
// this.interceptorsAndDynamicMethodMatchers 是代理对象中的所有拦截器
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 所有方法拦截器逻辑执行完之后,执行目标方法
return invokeJoinpoint();
}
// 逻辑走到这里说明代理对象中的拦截器尚未调用完,下面的逻辑就是逐个调用拦截器,
// 每调用完成一个,this.currentInterceptorIndex 会增1从而控制所有拦截器的执行逻辑
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.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
本系列文章链接合集 :
- 概述
- 执行信息记录对象ModelAndViewContainer的准备
- 请求参数的获取
- 控制器方法参数值绑定 HandlerMethodArgumentResolver
- 控制器方法参数值的验证 MethodValidationInterceptor
- 调用控制器方法本身
- 控制器方法返回值处理
- 包装返回结果 : 从ModelAndViewContainer对象构造ModelAndView对象