探究MVC的源码,那HandlerMapping 与 HandlerAdapter这两个组件也是绕不开的,我们从前面两篇文章大概也了解了这两个组件的作用。在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;
}
}
在 DispatcherServlet 的 doDispatch 中,依次调用拦截器的 preHandle、postHandle 和 afterCompletion。
3.2 HandlerMethod
@Controller
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
return "userDetail";
}
}
本质上封装了一个“类+方法”的对象,Spring就会把这个方法封装为一个 HandlerMethod
4. 总结
这篇文章主要说的是HandlerMapping 和 HandlerAdapter 是 Spring MVC 请求处理的核心支柱,我画一张图来诠释整个流程,以免大家比较混乱,整个调用流程如下:
HandMapping:负责找到能处理请求的 handlerHandlerMethod:封装了@Controller方法的对象HandlerExecutionChain:包含了handler+拦截器HandlerAdapter:负责执行handler