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

对于后面三个适配器,实现上都很简单,因为只需要把HttpServletRequest和HttpServletResponse对象透传下去,让子类自己去处理请求就好了,适配器本身并不需要处理过多复杂的事情。以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即可。

相关推荐
2301_780789662 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
学长毕设3 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn4 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川4 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵4 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
秋天的怀念_David4 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas1005 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin5 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php
霸道流氓气质6 小时前
智能客服组件:分层意图识别、RAG Advisor 与人工转接状态机的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
captain3766 小时前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis