前文 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(); } }