SonicsTorm 2019-06-27
本章我们主要分析Spring处理HandlerAdapter组件的处理流程以及其接口源码。概括来说,Spring使用HandlerAdapter组件分为两步,首先是注册组件,其次是处理用户请求,以下针对这两个过程进行详细的分析。
本系列文章是基于Spring5.0.5RELEASE。
一般情况下,在使用Spring MVC时,我们会配置在应用启动时加载和初始化Spring MVC组件,也就是在部署描述文件中配置<load-on-startup>1</load-on-startup>,启动过程会最终调用到DispatcherServlet的initStrategies(context)方法,此方法即为初始化九大组件的入口,当然也包括我们今天说要分析的HandlerAdapter,源码如下:
/** * 初始化策略对象 */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); // 初始化处理器适配器HandlerAdapter initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; // 在部署描述文件中可控制该参数 if (this.detectAllHandlerAdapters) { // 从应用上下文中查找HandlerAdapter Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList<>(matchingBeans.values()); // 对使用的HandlerAdapter进行排序,spring提供的只有RequestMappingHandlerAdapter实现了Ordered接口,其他都不具备排序功能 AnnotationAwareOrderComparator.sort(this.handlerAdapters); } } else { try { // 如果在部署描述文件中配置了detectAllHandlerAdapters=false,此时spring会加载名称为handlerAdapter的bean为处理器适配器 HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class); // 转化为集合赋给handlerAdapters属性 this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerAdapter later. } } // 如果未配置HandlerAdapter,注册默认的处理器适配器,即从DispatcherServlet.properties中获取的HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和ReqeustMappingHandlerAdapter if (this.handlerAdapters == null) { this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default"); } } }
以上就是Spring MVC对HandlerAdapter组件的注册过程。
应用在启动时完成了HandlerAdapter的注册,即具备了处理用户请求的能力,那么在用户发起请求时,请求会有DispatcherSerlvlet所拦截,最终调用其doDispatch方法进行处理,源码如下:
/** * 处理请求分发给handler */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { // 附件上传有关,后续分析multipartResolver时再详细分析 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 获取请求处理的HandlerExecutionChain对象,该对象组装了我们的handler和相关拦截器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 获取请求处理的处理器适配器,在getHandlerAdapter方法中进行适配策略的判断 // 参加下面getHandlerAdapter的方法详解 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 拦截器处理用户请求,即执行请求相关的拦截器方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 调用handler处理方法,由此,通过适配器模式就调用到了我们使用的handler的处理方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } /** * 返回handler对象的处理器适配器 */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 迭代处理器适配器策略,判断handler是否适配成功 for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } // 进行适配策略的判断 if (ha.supports(handler)) { return ha; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
以上就是HandlerAdatper处理用户请求源码分析。
通过前面两部分,我们分析了Spring MVC对HandlerAdapter组件的使用,包括注册和处理请求过程,接下来我们看一下给接口的定义,源码如下:
package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; public interface HandlerAdapter { /** * 判断适配器是否适配handler,适配策略由子类实现 */ boolean supports(Object handler); /* * 使用适配的handler执行用户请求 */ @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** * 返回资源的最后修改时间,如果handler实现类不支持可以返回-1 */ long getLastModified(HttpServletRequest request, Object handler); }
以上是HandlerAdapter接口的源码分析,如需自定义HandlerAdapter,只需要实现该接口,在supports方法中定义适配策略,并实现handle方法进行调用即可。
本文主要分析了Spring MVC使用HandlerAdapter组件处理用户请求的过程,从过程来看,用户可干预的也就是实现HanderApater接口,自定义处理器适配器。
接下来的几章将分析Spring MVC提供的HandlerAdapter适配策略,希望本节对大家能有帮助,谢谢。
最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!