HandlerAdapter
前文 02 Spring MVC 源码总结 - 内置处理器 HandlerMapping 分析
介绍了 SpringMVC 中的 handler 有多种实现方式, 实现 Controller 接口或实现 HttpRequestHandler 对象以及通过注解控制器的方式都可实现一个 handler。由于实现方式不一样,调用方式就不确定了,所以引入 HandlerAdapter。
适配器模式
适配器模式(Adapter Pattern),把一个类的接口变换成客户端所期待的另一种接口, Adapter模式使原本因接口不匹配(或者不兼容)而无法在一起工作的两个类能够在一起工作。
HandlerAdapter 类关系图
- HandlerAdapter
HandlerAdapter 作为父接口,定义了三个方法供子类实现
/**
* 是否支持该处理器
*/
boolean supports(Object handler);
/**
* 执行处理器,返回ModelAndView结果
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 返回请求的最新更新时间,如果不支持该操作,则返回-1即可
*/
long getLastModified(HttpServletRequest request, Object handler);
-
HttpRequestHandlerAdapter
用于处理实现HttpRequestHandler
接口的对象,在handler()方法中直接调用重写的handleRequest()方法即可
-
SimpleControllerHandlerAdapter
用于处理实现Controller
接口的对象,在handler()方法中直接调用重写的handleRequest()方法即可
-
RequestMappingHandlerAdapter
用于处理实现@Controller注解
,自定义方法的调用,后面具体分析
源码分析
DispatcherServlet::doDispatch() 中,取得 handler 对象后会根据 handler 匹配具体的 Adapter,然后调用重写的 handle() 方法执行业务流程
getHandlerAdapter()
遍历HandlerAdapter对象,调用重写的supports()方法获得当前handler对应的HandlerAdapter对象
handle()
这里重点介绍下基于注解实现自定义的方法的调用,也就是 RequestMappingHandlerAdapter::handle()
跟踪源码,到达关键的执行方法 invokeHandlerMethod()
,核心步骤:
- 解决数据绑定问题 @InitBinder
- 获取model相关的属性 @ModelAttribute
- 创建 HandlerMethod 对象,具备了返回值的处理功能,并且能够处理@ResponseStatus 注解
- 创建ModelAndViewContainer对象,用于保存model和View对象
- 创建AsyncWebRequest异步请求对象
- 创建WebAsyncManager异步请求管理器对象
- 执行具体调用
- 处理完请求后的后置处理
- 调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult
- 根据mavContainer创建了ModelAndView
- 如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 使用request和response创建ServletWebRequest对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 1. 解决数据绑定问题 @InitBinder
// 创建WebDataBinderFactory对象,此对象用来创建WebDataBinder对象,进行参数绑定,
// 实现参数跟String之间的类型转换,ArgumentResolver在进行参数解析的过程中会用到WebDataBinder
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 2. 获取model相关的属性 @ModelAttribute
// 创建ModelFactory对象,此对象主要用来处理model,主要是两个功能,1是在处理器具体处理之前对model进行初始化,2是在处理完请求后对model参数进行更新
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 3. 创建 HandlerMethod 对象,具备了返回值的处理功能,并且能够处理@ResponseStatus 注解
// 创建ServletInvocableHandlerMethod对象,并设置其相关属性,实际的请求处理就是通过此对象来完成的,参数绑定、处理请求以及返回值处理都在里边完成
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数处理器
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
// 设置返回值处理器
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// 设置参数绑定工厂对象
invocableMethod.setDataBinderFactory(binderFactory);
// 设置参数名称发现器
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 4.创建ModelAndViewContainer对象,用于保存model和View对象
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 将flashmap(参数传递时的参数结构)中的数据设置到model中
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
// 根据配置对ignoreDefaultModelOnRedirect进行设置
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 5.创建AsyncWebRequest异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 6.创建WebAsyncManager异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
// 如果当前异步请求已经处理并得到结果,则将返回的结果放到mavContainer对象中,然后将invocable对象进行包装转换,转成需要的执行对象然后开始执行
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
// 转换具体的invocable执行对象
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 7.执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 8.处理完请求后的后置处理,此处一共做了三件事,
// 1、调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult
// 2、根据mavContainer创建了ModelAndView
// 3、如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
// 标记请求完成
webRequest.requestCompleted();
}
}