本章咱們主要分析Spring處理HandlerAdapter組件的處理流程以及其接口源碼。歸納來講,Spring使用HandlerAdapter組件分爲兩步,首先是註冊組件,其次是處理用戶請求,如下針對這兩個過程進行詳細的分析。java
本系列文章是基於Spring5.0.5RELEASE。ios
通常狀況下,在使用Spring MVC時,咱們會配置在應用啓動時加載和初始化Spring MVC組件,也就是在部署描述文件中配置<load-on-startup>1</load-on-startup>,啓動過程會最終調用到DispatcherServlet的initStrategies(context)方法,此方法即爲初始化九大組件的入口,固然也包括咱們今天說要分析的HandlerAdapter,源碼以下:web
/** * 初始化策略對象 */ 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組件的註冊過程。spring
應用在啓動時完成了HandlerAdapter的註冊,即具有了處理用戶請求的能力,那麼在用戶發起請求時,請求會有DispatcherSerlvlet所攔截,最終調用其doDispatch方法進行處理,源碼以下:app
/** * 處理請求分發給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處理用戶請求源碼分析。async
經過前面兩部分,咱們分析了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方法進行調用便可。post
本文主要分析了Spring MVC使用HandlerAdapter組件處理用戶請求的過程,從過程來看,用戶可干預的也就是實現HanderApater接口,自定義處理器適配器。學習
接下來的幾章將分析Spring MVC提供的HandlerAdapter適配策略,但願本節對你們能有幫助,謝謝。this
最後建立了qq羣方便你們交流,可掃描加入,同時也可加我qq:276420284,共同窗習、共同進步,謝謝!