Spring MVC之HandlerAdapter

1. 前言

Spring MVC没有限制Handler的类型,Handler可以以任何形式存在,内置的Handler就有四种类型:

  • HandlerMethod
  • Controller
  • HttpRequestHandler
  • Servlet

开发者还可以自定义Handler,面对各种各样类型的Handler,Spring MVC再也不能简单直接的面向接口编程了。于是Spring MVC采用了适配器模式,通过不同的适配器去协调不同的Handler工作,适配器本身是很容易抽象成接口的,所以Spring MVC又可以愉快的面向接口编程了。

2. HandlerAdapter

java 复制代码
public interface HandlerAdapter {
    /**
     * 适配器是否支持给定的Handler?
     */
    boolean supports(Object handler);

    /**
     * 协调Handler处理请求,返回结果
     */
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    /**
     * 获取资源最后修改的时间戳,以确定是否返回304让浏览器使用缓存
     */
    long getLastModified(HttpServletRequest request, Object handler);

}

HandlerAdapter接口定义很简单,Spring MVC首先会遍历所有的HandlerAdapter,依次通过supports()判断当前适配器是否支持处理给定的Handler?如果支持,那么就调用handle()让适配器去协调Handler处理请求,返回结果。

DispatcherServlet获取Handler对应的适配器:

java 复制代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
            "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

让适配器去处理请求,返回ModelAndView:

java 复制代码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

3. 内置适配器

Spring MVC内置了四种类型的Handler,对应的也就存在四种HandlerAdapter**。**

Handler HandlerAdapter
HandlerMethod RequestMappingHandlerAdapter
Controller SimpleControllerHandlerAdapter
HttpRequestHandler HttpRequestHandlerAdapter
Servlet SimpleServletHandlerAdapter

对于后面三个适配器,实现上都很简单,因为只需要把HttpServletRequestHttpServletResponse对象透传下去,让子类自己去处理请求就好了,适配器本身并不需要处理过多复杂的事情。以SimpleControllerHandlerAdapter为例:

java 复制代码
public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        // 只要Handler是Controller类型,就支持处理
        return (handler instanceof Controller);
    }

    @Override
    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 转换类型,把request和response透传给Handler处理即可
        return ((Controller) handler).handleRequest(request, response);
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}
  • supports()判断很简单,只要Handler属于Controller类型即可。
  • handle()更简单了,把request和response透传给Handler处理即可。

真正复杂的是RequestMappingHandlerAdapter,也就是被@RequestMapping注解标记的方法,Handler对应的类是org.springframework.web.method.HandlerMethod。它的处理过程主要有三步:

  1. 准备HandlerMethod需要的参数。
  2. 反射调用目标方法,处理请求。
  3. 将返回结果封装成ModelAndView。

都使用Spring MVC了,相信大家也不会自己去操作HttpServletRequest获取请求参数了,更多的是使用@RequestParam@PathVariable@RequestHeader@RequestBody等注解让Spring MVC绑定参数,所以光是第一步准备参数就非常复杂,值得另起篇幅单独记录;第二步反而是最简单的,直接反射调用目标方法即可;第三步将返回结果封装成ModelAndView,现在基本都前后端分离了,一般通过@ResponseBody直接响应JSON即可。

相关推荐
衍生星球14 分钟前
JSP 程序设计之 JSP 基础知识
java·web·jsp
m0_7493175214 分钟前
力扣-字母异位词
java·算法·leetcode·职场和发展
黑暗也有阳光25 分钟前
java中为什么hashmap的大小必须是2倍数
java·后端
fatsheep洋29 分钟前
XSS-DOM-1
java·前端·xss
七七软件开发1 小时前
一对一交友小程序 / APP 系统架构分析
java·python·小程序·系统架构·php
TDengine (老段)1 小时前
TDengine 中 TDgpt 异常检测的数据密度算法
java·大数据·算法·时序数据库·iot·tdengine·涛思数据
YuTaoShao1 小时前
【LeetCode 热题 100】155. 最小栈
java·算法·leetcode
程序视点1 小时前
Java语言核心特性全解析:从面向对象到跨平台原理
java·后端·java ee
Warren982 小时前
MySQL查询语句详解
java·开发语言·数据库·mysql·算法·蓝桥杯·maven