Spring MVC : 控制器方法处理请求的过程分析 - 5. 调用控制器方法本身

本系列文章的上一篇 : 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);
		}
	}

本系列文章链接合集 :

  1. 概述
  2. 执行信息记录对象ModelAndViewContainer的准备
  3. 请求参数的获取
  4. 控制器方法参数值绑定 HandlerMethodArgumentResolver
  5. 控制器方法参数值的验证 MethodValidationInterceptor
  6. 调用控制器方法本身
  7. 控制器方法返回值处理
  8. 包装返回结果 : 从ModelAndViewContainer对象构造ModelAndView对象
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值