SpringMVC 控制器方法(handler)适配器 - HandlerAdapter
SpringMVC 控制器方法(handler)适配器 - HandlerAdapter
简单的源码分析
HandlerAdapter
是一个 MVC 框架 SPI 接口,通过此接口,我们可以高度自定义核心 MVC 工作流。
(控制器 handler 可以是任意类型),任何一种类型的 handler 都必须有一个 HandlerAdapter
支持,否则此种类型的 handler 将无法解析请求,
通过 HandlerAdapter
接口,可以实现对 DispatcherServlet
的无限扩展。DispatcherServlet
通过 HandlerAdapter
调用 handler,这意味着 DispatcherServlet
不包含特定于任何类型的 handler 的代码。这让 DispatcherServlet
保持了低耦合的效果。
注意,handler 可以是任意类型,当然也可以是 Object 类型。这是为了使来自其他框架的 handler 无需额外编码就可以与 SpringMVC 框架集成,并且允许不实现任何特定接口的带特定注解的 handler。
此接口不适用于应用程序开发人员。它适用于希望开发自己的 web 工作流的处理程序的开发人员。
接口源码:
public interface HandlerAdapter {
// 判断是否支持特定类型的handler,一个HandlerAdapter一般支持持一个类型的 handler
boolean supports(Object handler);
// 根据传入的 handler 处理传入的 request 请求,并最终返回一个 ModelAndView, 这个 handler 一般都是先通过 supports 方法判断过此HandlerAdapter支持的handler.
// 具体的实现非常自由,想做什么都可以
// 一般调用 handler 处理 request 前会做非常多的准备工作,
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 不知道啥意思
long getLastModified(HttpServletRequest request, Object handler);
}
一般我们都要调用 HandlerAdapter#supports
方法来检查当前 HandlerAdapter
是否支持此 handler
,如果支持,才会调用 HandlerAdapter#handle
方法来处理请求
类继承树:
适配器的意义
一般 handler(处理器)这个概念是没有固定类型的,大部分的时候,是控制器方法(@Controller
修饰的类中的方法),有的时候是 DefaultServletHttpRequestHandler
,有的时候是 ParameterizableViewController
,所以,我们只能用 Object
来承接 handler 这个概念,同时,我们还需要对不同的类型的 handler 进行适配,让各种类型的 handler 都可以适配进统一的流程处理(DispatcherServlet#doDispatch
),于是适配器 HandlerAdapter
应运而生。,同时在适配器中也可以进行一些调用 handler 前的前置工作,比如,在调用控制器方法这一类 handler 的时候,会进行控制器方法参数的填充,同时进行参数验证等等。
我们可以通过 HandlerAdapter#supports
方法查看此适配器支持何种类型的 handler,
-
HandlerMethod
类型的 handler,也就是我们见得最多的,也是写的最多的@Controller
修饰的类中的方法,即控制器方法,通过RequestMappingHandlerAdapter
适配。 -
HttpRequestHandler
接口的实现类,比如DefaultServletHttpRequestHandler
:WebMvcConfigurationSupport#configureDefaultServletHandling
配置的处理静态资源的默认的请求处理器,比如ResourceHttpRequestHandler
:WebMvcConfigurationSupport#addResourceHandlers
配置的将请求 URL 和资源所处的路径进行映射的请求处理器,通过HttpRequestHandlerAdapter
适配。 -
Controller
接口的实现类,比如ParameterizableViewController
:WebMvcConfigurationSupport#addViewControllers
方法配置的用来进行请求 URL 直接跟视图映射的处理器(虽然叫 Controller 但是是处理器), 通过SimpleControllerHandlerAdapter
适配。这是一个函数式接口,包名为
org.springframework.web.servlet.mvc
,而不是前面说到的注解接口@Controller
,那个包名为org.springframework.stereotype
。 -
原生的 Servlet 作为控制器,SpringMVC 也可以处理,通过
SimpleServletHandlerAdapter
适配,用的少,默认不添加。 -
HandlerFunction
接口的实现类,通过HandlerFunctionAdapter
适配,用的少。HandlerFunction
目前就一个实现类ResourceHandlerFunction
HandlerFunction
实际上代表的是函数式WEB
。Spring 框架给我们提供了两种 http 端点暴露方式来隐藏 servlet 原理,一种就是这多年大家都在使用的基于注解的形式
@Controller
或@RestController
以及其他的注解如@RequestMapping
、@GetMapping
等等。另外一种是基于路由配置RouterFunction
和HandlerFunction
的,称为“函数式 WEB”。参考博客:Spring 5 MVC 中的 Router Function 使用_mob604756fb8908的技术博客_51CTO博客
初始化
DispatcherServlet#initHandlerAdapters
和 DispatcherServlet#getDefaultStrategies
DispatcherServlet#initHandlerAdapters
请看《SpringMVC-DispatcherServlet 源码分析.md》的initStrategies
小节
在《SpringMVC- 第五篇:视图》就有过关于
DispatcherServlet#getDefaultStrategies
的研究。
一般用不到 DispatcherServlet#getDefaultStrategies
,通过注解配置 SpringMVC 的时候(实际上在 WebMvcConfigurationSupport
中),会自动注入在应用上下文中注入默认几个 HandlerAdapter
的相应类型的 Bean,
-
RequestMappingHandlerAdapter
-
HandlerFunctionAdapter
-
HttpRequestHandlerAdapter
-
SimpleControllerHandlerAdapter
具体生效
doDispatch 执行流程
-
经过
HandlerMapping
进行处理器映射,获取 handler,实际上获取的是包含拦截器的处理器执行链HandlerExecutionChain
-
通过
HandlerExecutionChain
中最终的 handler,获取适配器HandlerAdapter
-
调用拦截器的处理器执行链的前置方法
HandlerExecutionChain#applyeHandle
-
执行
HandlerAdapter#handle
方法执行处理器,获得ModelAndView
-
调用拦截器的处理器执行链的后置方法
HandlerExecutionChain#applyPostHandle
-
调用
DispatcherServlet#processDispatchResult
处理ModelAndView
,如果有错误,就已经异常处理,渲染异常解析HandlerExceptionResolver
返回的ModelAndView
,如果没有错误,正常解析ModelAndView
,并在最后调用拦截器的处理器执行链的完成时方法HandlerExecutionChain#afterCompletion
。
DispatcherServlet#doDispatch
中的 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
DispatcherServlet
的 getHandlerAdapter
方法则是通过遍历字段 handlerAdapters
,调用 HandlerAdapter
的 supports
方法,检查适配器是否支持当前 handler,只要找到了支持的适配器就直接返回,所以 handlerAdapters
中的 HandlerAdapter
的顺序很重要。
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");
}
应用上下文中会注入默认的相应类型的 Bean,比如在 WebMvcConfigurationSupport 中,该有的都有四种。

比 xml 配置 SpringMVC 多了一类,而且顺序也不一样,
通过 XML 配置的 HandlerAdapter
RequestMappingHandlerAdapter
具体请看《SpringMVC-RequestMappingHandlerAdapter 源码解析.md》
HttpRequestHandlerAdapter
有时间再来研究,TODO
SimpleControllerHandlerAdapter
有时间再来研究,TODO