摘要:概述根據(jù)規(guī)范,當(dāng)用戶請求到達(dá)應(yīng)用時(shí),由的方法進(jìn)行處理,對于而言,處理用戶請求的入口為,通過其父類的攔截處理。最后創(chuàng)建了群方便大家交流,可掃描加入,同時(shí)也可加我,共同學(xué)習(xí)共同進(jìn)步,謝謝
概述
根據(jù)Servlet規(guī)范,當(dāng)用戶請求到達(dá)應(yīng)用時(shí),由Servlet的service()方法進(jìn)行處理,對于Spring MVC而言,處理用戶請求的入口為DispatcherServlet,通過其父類FrameworkServlet的service()攔截處理。
FrameworkServlet用戶請求的入口方法為service(request,response),源碼如下:
/** * Override the parent class implementation in order to intercept PATCH requests. */ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); // Spring3.0增加了PATCH方法攔截處理 if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { // GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE super.service(request, response); } }
該方法重寫了HttpServlet的service()方法,并增加了PATCH請求的攔截處理,其他諸如GET、POST、PUT等請求則調(diào)用父類的service方法,HttpServlet類的service()方法就是根據(jù)請求類型進(jìn)行不同的路由處理,如為GET請求,則路由至doGet()方法處理,以此類推,此處省略源碼。
假如用戶請求為GET,則路由到子類(FrameworkServlet)的doGet()方法進(jìn)行處理,doGet()源碼如下:
@Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
其實(shí),所有類型的請求最終都由processRequest()方法進(jìn)行處理,processRequest方法源碼如下:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; // LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); // 構(gòu)建請求(request)的LocalContext上下文,提供基本的作為當(dāng)前地區(qū)的主要語言環(huán)境 LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); // 構(gòu)建請求(request)的ServletRequestAttributes對象,保存本次請求的request和response ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); // 異步請求處理的管理核心類 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); // 綁定request context上線到當(dāng)前線程 initContextHolders(request, localeContext, requestAttributes); try { // 模板方法,調(diào)用子類(DispatcherServlet)的doService方法進(jìn)行處理 doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { // 接觸請求線程與LocalContext和RequestAttributes的綁定 resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } if (logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", failureCause); } else { if (asyncManager.isConcurrentHandlingStarted()) { logger.debug("Leaving response open for concurrent processing"); } else { this.logger.debug("Successfully completed request"); } } } // 發(fā)布ApplicationEvent事件,可由ApplicationListener進(jìn)行監(jiān)聽 // 繼承ApplicationListener接口,實(shí)現(xiàn)onApplicationEvent()接口,并注冊到spring容器,即可捕獲該事件 publishRequestHandledEvent(request, response, startTime, failureCause); } }DispatcherServlet
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name "" + getServletName() + """ + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // 如果是include請求,保存request attribute快照數(shù)據(jù),并在finally中進(jìn)行還原 MapattributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<>(); Enumeration> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // 把環(huán)境上下文設(shè)置到請求域中 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this.flashMapManager != null) { FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } try { // 調(diào)用請求處理方法 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } } // 請求處理關(guān)鍵方法 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 { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. 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; } // Actually invoke the 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); } } } }
doDispatch()是Spring MVC中重要的方法,用戶處理用戶請求,其主要經(jīng)過過程如下:
獲取當(dāng)前請求的Handler
獲取當(dāng)前請求的Handler Adapter
執(zhí)行preHandle方法
執(zhí)行Handle方法,即Controller中的方法
執(zhí)行postHandle方法
處理返回結(jié)果
總結(jié)本文簡要概述了Spring MVC處理用戶請求過程中所涉及的主要方法,對請求處理的流程做了概述,后續(xù)將對內(nèi)部細(xì)節(jié)進(jìn)行分析,以加深理解。
最后創(chuàng)建了qq群方便大家交流,可掃描加入,同時(shí)也可加我qq:276420284,共同學(xué)習(xí)、共同進(jìn)步,謝謝!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/71103.html
摘要:概述本章我們主要分析處理組件的處理流程以及其接口源碼。概括來說,使用組件分為兩步,首先是注冊組件,其次是處理用戶請求,以下針對這兩個(gè)過程進(jìn)行詳細(xì)的分析。本系列文章是基于。接下來的幾章將分析提供的適配策略,希望本節(jié)對大家能有幫助,謝謝。 概述 本章我們主要分析Spring處理HandlerAdapter組件的處理流程以及其接口源碼。概括來說,Spring使用HandlerAdapter組...
摘要:概述上一節(jié)我們分析了的初始化過程,即創(chuàng)建并注冊,本章我們分析下的請求處理過程,即查找。本系列文章是基于。最后創(chuàng)建了群方便大家交流,可掃描加入,同時(shí)也可加我,共同學(xué)習(xí)共同進(jìn)步,謝謝 概述 上一節(jié)我們分析了RequestMappingHandlerMapping的初始化過程,即創(chuàng)建并注冊HandlerMehtod,本章我們分析下RequestMappingHandlerMapping的請求...
摘要:需求根據(jù)客戶端環(huán)境,界面顯示不同的國旗圖案。選擇的技術(shù)方案可利用提供的國際化和主題定制來解決。注意此時(shí)返回的中沒有國際化及主題相關(guān)的信息。修改請求參數(shù)的值為荷蘭,即后再發(fā)起請求,結(jié)果如下與預(yù)期一致,測試通過。 概述 以上分析了Spring MVC的LocaleResolver和ThemeResolver兩個(gè)策略解析器,在實(shí)際項(xiàng)目中很少使用,尤其是ThemeResolver,花精力去分析...
摘要:與類圖對比,類繼承自抽象類,其又繼承自抽象類,再往上繼承關(guān)系與一致。創(chuàng)建初始化上一章我們分析了的創(chuàng)建初始化過程,的創(chuàng)建初始化過程與一樣,方法的入口在抽象類中的方法。至此,代碼編寫完畢。 概述 本節(jié)我們繼續(xù)分析HandlerMapping另一個(gè)實(shí)現(xiàn)類BeanNameUrlHandlerMapping,從類的名字可知,該類會(huì)根據(jù)請求的url與spring容器中定義的bean的name屬性值...
摘要:概述通過前三章的分析,我們簡要分析了和,但對攔截器部分做詳細(xì)的分析,攔截器的加載和初始化是三個(gè)相同的部分。 概述 通過前三章的分析,我們簡要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但對攔截器部分做詳細(xì)的分析,攔截器的加載和初始化是三個(gè)HandlerMapping相...
閱讀 2917·2021-10-19 10:09
閱讀 3136·2021-10-09 09:41
閱讀 3384·2021-09-26 09:47
閱讀 2696·2019-08-30 15:56
閱讀 602·2019-08-29 17:04
閱讀 992·2019-08-26 11:58
閱讀 2511·2019-08-26 11:51
閱讀 3362·2019-08-26 11:29