Spring MVC -HandlerMapping 与 HandlerAdapter 的实现

280 阅读4分钟

探究MVC的源码,那HandlerMappingHandlerAdapter这两个组件也是绕不开的,我们从前面两篇文章大概也了解了这两个组件的作用。在HTTP请求分配到DispatcherServlet后,DispatcherServlet会调用HandlerMapping来获取HandlerExecutionChain,然后根据处理器类型来调用HandlerAdapter来执行处理器逻辑。

  • HandlerMapping:根据请求的URL、HTTP方法等信息,确定哪个处理器负责处理该请求,并返回一个HandlerExecutionChain对象,其中包含处理器和拦截器。
  • HandlerAdapter:适配并调用处理器,屏蔽DispatcherServlet对处理器具体实现的依赖,支持多种处理器类型。

在开始说细节之前,我先说一下例子:首先要记住的是handler其实就是处理请求的对象,可能是个方法、是个类或者一个接口,Spring MVC会根据请求URL匹配到这个对象,然后执行它来处理请求。

我们把handler当成是厨师

  • 用户点餐(发起请求)
  • 系统通过HandlerMapping找到哪个厨师负责这道菜(找到handler)
  • 系统用合适的工具(HandlerAdapter)通知厨师做菜(调用handler)
  • 厨师做好后返回菜品(返回视图和JSON)

大家牢牢记住这个例子,然后往下看,不然就会很晕!

1. HandlerMapping 的实现

1.1 HandlerMapping接口

整个源码定义很简单:

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

这个就是根据请求返回处理器以及拦截器链。

1.2 重要的实现类

RequestMappingHandlerMapping,这个是我们最常用的一个实现类,比如我们在Controller层经常会写这样几个注解@RequestMapping@GetMapping。整体的执行流程是这样的:启动时扫描Bean的时候就会扫描所有@Controller,找到了标注@RequestMapping、@GetMapping标注的方法,注册一个URL->Handler的映射表(HandlerMethod)

我们来看一下初始化流程的代码: 首先启动时调用这个

protected void initHandlerMethods() {
    // 获取所有 BeanName
    for (String beanName : getCandidateBeanNames()) {
        detectHandlerMethods(beanName);
    }
}

进一步看detectHandlerMethods这个代码:

protected void detectHandlerMethods(Object handler) {
    // 遍历方法
    for (Method method : userDeclaredMethods) {
        RequestMappingInfo mapping = getMappingForMethod(method, handlerType);
        if (mapping != null) {
            registerHandlerMethod(handler, method, mapping);
        }
    }
}

这里就会把所有映射好的handler缓存在MappingRegistry中。

另外还有其他的实现类,比如按照Bean的名字作为URL映射的,我这里就不多介绍了,目前用的最多的是这个。

1.3 自定义扩展

每次我们谈及源码都会说这个问题,因为Spring确实提供了良好的扩展性,支持我们自定义扩展。在这里我们也可以自定义HandlerMapping来实现自定义映射逻辑。

这里你就需要去继承 AbstractHandlerMapping ,例如你可以自定义根据请求头、或者Token,只要将其注册为Bean就可以参与Handler查找链。

2. HandlerAdapter的实现

我们知道当DispatcherServlet找到了HandlerMethod但不知道怎么调用它,于是就交给HandlerAdapter去执行。

2.1 核心接口

HandlerAdapter接口定义了处理器的适配和调用逻辑:

public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    long getLastModified(HttpServletRequest request, Object handler);
}

handler执行处理器逻辑

2.2 常见的实现类

MVC里内置了多个HandlerAdapter,可以根据请求处理对象的类型使用不同的Adapter:

  • RequestMappingHandlerAdapter:这是基于注解的控制器
  • HttpRequestHandlerAdapter:最底层的处理器,接管HTTP请求
  • SimpleControllerHandlerAdapter:这个是早期接口风格的控制器

Spring会按顺序遍历所有的Adapter,调用supports方法,找到能处理该请求的Adapter,然后调用handler方法。

2.3 源码分析:RequestMappingHandlerAdapter

这是我们最常用的 HandlerAdapter实现,处理注解控制器方法。

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {
    // 实现了 HandlerAdapter 接口
}

当调用handler() 方法时,内部执行流程大概是下面这样:

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    HandlerMethod handlerMethod = (HandlerMethod) handler;

    // 1. 解析参数(如@PathVariable、@RequestBody 等)
    // 2. 调用 Controller 方法
    // 3. 封装结果(返回值 -> ModelAndView 或 @ResponseBody JSON)

    return invokeHandlerMethod(request, response, handlerMethod);
}

整个调用链关键是:参数解析器、返回值处理器、异常处理器

完整的源码是这样的:

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter {
    @Override
    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        InvocableHandlerMethod invocable = createInvocableHandlerMethod(handlerMethod);
        invocable.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        invocable.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

        ServletInvocableHandlerMethod servletInvocable = new ServletInvocableHandlerMethod(invocable);
        servletInvocable.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
        servletInvocable.invokeAndHandle(webRequest, mavContainer);

        return getModelAndView(mavContainer, handlerMethod, request);
    }
}

另外,这个组件也支持自定义,可以实现自己的HandlerAdapter

3. 其他关键点

3.1 HandlerExecutionChain

HandlerExecutionChain表示的一次完整的请求处理链条:我们来看一下源码是怎么实现的

public class HandlerExecutionChain {
    private final Object handler;
    private final List<HandlerInterceptor> interceptors;

    public boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for (HandlerInterceptor interceptor : this.interceptors) {
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
        }
        return true;
    }
}

DispatcherServletdoDispatch 中,依次调用拦截器的 preHandlepostHandleafterCompletion

3.2 HandlerMethod

@Controller
public class UserController {

    @GetMapping("/user/{id}")
    public String getUser(@PathVariable Long id) {
        return "userDetail";
    }
}

本质上封装了一个“类+方法”的对象,Spring就会把这个方法封装为一个 HandlerMethod

4. 总结

这篇文章主要说的是HandlerMappingHandlerAdapter 是 Spring MVC 请求处理的核心支柱,我画一张图来诠释整个流程,以免大家比较混乱,整个调用流程如下:

image.png

  • HandMapping:负责找到能处理请求的 handler
  • HandlerMethod:封装了@Controller方法的对象
  • HandlerExecutionChain:包含了handler+拦截器
  • HandlerAdapter:负责执行handler