Spring MVC分析篇——HandlerAdapter

一.HandlerAdapter设计原理

  SpringMVC的第一步,通过HandleMapping找到了某个请求对应的Handler,现在Handler有了,但是不同的handler的执行逻辑完全不一样,实现了Controller接口的handler,直接调用handler的handleRequest(……)方法就行,使用RequestMapping注解的handler,需要找到具体的方法再执行。所以为了统一Handler的处理逻辑,最合适的方法是采用适配器模式。

那么一个Handler适配器需要具备哪些功能呢?

  1. 统一的执行方法,方法的入参很简单,HttpServletRequest、HttpServletResponse和具体的handler,出参需要定义一个统一的模型,该模型尤为重要,一方面需要包括所有的内容请求处理的数据,另一方面需要指出这些数据的处理方式
  2. 第一步,我们有了一个Handler,那么第二步需要做的是根据handler找到handler对应的HandlerAdapter
public interface HandlerAdapter {

	// 判断该HandlerAdapter是否支持指定的handler
	boolean supports(Object handler);

    // 执行handler
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	long getLastModified(HttpServletRequest request, Object handler);

}

public class ModelAndView {

	private Object view;

	private ModelMap model;

	private HttpStatus status;

	private boolean cleared = false;
}

HandlerAdapter继承关系:
《Spring MVC分析篇——HandlerAdapter》

  1. SimpleControllerHandlerAdapter:适配实现了Controller接口的handler
  2. RequestMappingHandlerAdapter:适配通过@RequestMapping注解的handler,@RequestMapping注解的方法,会封装为HandleMethod对象,HandleMethod对象也就是真正的handler
  3. HttpRequestHandler:适配实现了HttpRequestHandler接口的handler
  4. SimpleServletHandlerAdapter:适配实现了Servlet接口的handler

除了RequestMappingHandlerAdapter外,其他的HandlerAdapter其实都比较简单,下面我们详细的分析一下RequestMappingHandlerAdapter。

二.RequestMappingHandlerAdapter

处理一个请求大致上都是下面3个步骤:

  1. 入参解析
  2. 执行方法
  3. 出参转换

  一个http请求的入参,基于不同的content-type,会有不一样的取值逻辑,取到具体的值之后,根据方法参数上配置的不同,转换逻辑又不一样。所以整个入参解析就尤为复杂。不过,http请求的入参虽然千差万别,但是方法的入参是固定的,所以根据方法需要的入参,再到请求入参中取查找,就变得容易多了。

基于此,就有了HandlerMethodArgumentResolver接口。

public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

	Object resolveArgument(MethodParameter parameter,  ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest,  WebDataBinderFactory binderFactory) throws Exception;

}

再来看看HandlerMethodArgumentResolver接口的继承关系。
《Spring MVC分析篇——HandlerAdapter》
下面,我们来看看几个比较常见的HandlerMethodArgumentResolver的使用方式及解析过程

  1. ServletRequestMethodArgumentResolver
// 支持的参数类型,其中最常见的有ServletRequest、MultipartRequest
public boolean supportsParameter(MethodParameter parameter) {
	Class<?> paramType = parameter.getParameterType();
	return (WebRequest.class.isAssignableFrom(paramType) ||
			ServletRequest.class.isAssignableFrom(paramType) ||
			MultipartRequest.class.isAssignableFrom(paramType) ||
			HttpSession.class.isAssignableFrom(paramType) ||
			(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
			Principal.class.isAssignableFrom(paramType) ||
			InputStream.class.isAssignableFrom(paramType) ||
			Reader.class.isAssignableFrom(paramType) ||
			HttpMethod.class == paramType ||
			Locale.class == paramType ||
			TimeZone.class == paramType ||
			ZoneId.class == paramType);
}
  1. ServletResponseMethodArgumentResolver
// 支持的参数类型,其中最常见的有ServletResponse
public boolean supportsParameter(MethodParameter parameter) {
	Class<?> paramType = parameter.getParameterType();
	return (ServletResponse.class.isAssignableFrom(paramType) ||
			OutputStream.class.isAssignableFrom(paramType) ||
			Writer.class.isAssignableFrom(paramType));
}
  1. RequestParamMapMethodArgumentResolver:解析@RequestParam注解
public boolean supportsParameter(MethodParameter parameter) {
	RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
	return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
			!StringUtils.hasText(requestParam.name()));
}
    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/u011983531/article/details/83752679
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞