DispatcherServlet 请求处理主逻辑 : 3. 通过 HandlerAdapter 执行 Handler

该系列上一篇 : DispatcherServlet 请求处理主逻辑 : 2. 选择 Handler 对应的 HandlerAdapter

本文代码版本 : spring-webmvc-5.1.5.RELEASE

DispatcherServlet请求处理主逻辑(#doDispatch)找到针对当前请求的Handler以及HandlerAdapter之后,就是使用HandlerAdapter执行该Handler从而处理当前请求了。相应的调用语句如下:

// 1. 这里 mappedHandler 是所找到的 Handler, 类型为 HandlerExecutionChain
// 相当于 : N HandlerInterceptor 包裹一个 Handler
// 2. 这里 mv 是一个类型为 ModelAndView 的对象
// 3. 这里 ha 是所找到的 HandlerAdapter

// 在调用 Handler 处理请求之前,应用各个 HandlerInterceptor 的前置拦截处理逻辑  preHandle 
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

// 各个HandlerInterceptor#preHandle前置处理逻辑应用完成且都返回true,
// 现在需要通过 ha 调用相应的 Handler 了
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 注意 : 这里 mv 存在为 null 的情况,比如开发人员在控制器方法上使用了
// @ResponseBody, 则最终返回给客户端的是JSON/XML之类的数据,而不需要
// 视图渲染,此时 mv 就会为 null。不过这种情况下虽然 mv 为null,当前
// 处理流程并不会结束,还是会继续,但下面的步骤会考虑该情况进行相应的处理。

// 这里有一些异步处理相关的代码,为了方便描述请求处理主逻辑,这里将其删除
// ... 

// 通过 ha 调用相应的 Handler 处理请求结束,现在对处理结果 mv 做个微调 :
// 如果 mv 中不含视图,并且能找到一个处理该请求的默认视图,则将该默认视图
// 设置到 mv 中
applyDefaultViewName(processedRequest, mv);

// 现在已经使用 Handler 处理了请求,结果是 mv 并且已经做了是否应用默认视图的微调,
// 现在需要应用各个 HandlerInterceptor 的后置拦截处理逻辑 postHandle 了
mappedHandler.applyPostHandle(processedRequest, response, mv);

概括来讲,上面使用HandlerAdapter执行该Handler处理请求的逻辑主要分为4个小步骤 :

  1. 应用各个HandlerInterceptor的前置拦截处理逻辑preHandle;
  2. 使用HandlerAdapter执行Handler以处理请求,返回结果ModelAndView mv;
  3. 对结果mv做是否应用默认视图的调整;
  4. 应用各个HandlerInterceptor的后置拦截处理逻辑postHandle;

接下来,我们继续深入,看看以上各个小步骤都做了些什么 。

1. 应用前置拦截处理逻辑

// 	类 HandlerExecutionChain 代码片段
    /**
	 * Apply preHandle methods of registered interceptors.
	 * @return true if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
	 */
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

2. 执行Handler处理请求

这个小步骤的逻辑是使用HandlerAdapter执行Handler以处理请求,返回结果ModelAndView mv。至于执行的细节,要取决于HandlerAdapter实现类。如果对此想了解更多,可以参考一下Spring MVC HandlerAdapter : 控制器方法适配器 RequestMappingHandlerAdapter,这是一个针对控制器方法的HandlerAdapter,换句话讲,开发人员通过@Controller注解定义的类中使用了@RequestMapping注解这样的方法,都是通过RequestMappingHandlerAdapter来执行的。

3. 检查是否需要应用缺省视图

	/**
	 * Do we need view name translation?
	 */
	private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
		if (mv != null && !mv.hasView()) {
			String defaultViewName = getDefaultViewName(request);
			if (defaultViewName != null) {
				mv.setViewName(defaultViewName);
			}
		}
	}

4. 应用后置拦截处理逻辑

// 	类 HandlerExecutionChain 代码片段
	/**
	 * Apply postHandle methods of registered interceptors.
	 */
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

通过上面的分析,我们可以看到DispatcherServlet请求处理主逻辑是如何使用各个组件协调完成请求处理的。并且,使用HandlerAdapter执行Handler处理完请求之后,输出的结果是一个ModelAndView mv,该对象持有两部分信息 :

  1. 用于渲染视图的数据,也就是Model;
  2. 视图View,可能是View对象,也可能是View的名称;
    该结果会被DispatcherServlet请求处理主逻辑下一步骤消费用于生成最终返回给客户端的视图数据。

上面的分析仅限于没有遇到异常的情况,那么,如果遇到了异常,又会怎样呢?实际上,以上步骤调用被一个try块包围,一旦遇到Exception,或者是Throwable,最终都会catch捕获并包装成一个异常对象(变量名称使用dispatchException),该异常对象dispatchException和上面提到的mv一样,也会提供给下一步骤的处理逻辑使用。

相关文章

  • Spring MVC : DispatcherServlet请求处理的主逻辑(文字版)
  • Spring MVC : 概念模型 HandlerAdapter
  • Spring MVC : WebMvcConfigurationSupport 中定义的 HandlerAdapter 组件
  • Spring MVC : 框架提供的 HandlerAdapter 实现
  • Spring MVC DispatcherServlet 策略初始化 – initHandlerAdapters
  • DispatcherServlet 请求处理主逻辑 : 1. 选择 Handler
  • DispatcherServlet 请求处理主逻辑 : 2. 选择 Handler 对应的 HandlerAdapter

你可能感兴趣的:(Spring,MVC,分析)