您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)使用SpringMVC請求怎么對handler進(jìn)行映射,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
前臺發(fā)送給后臺的訪問請求是如何找到對應(yīng)的控制器映射并執(zhí)行后續(xù)的后臺操作呢,其核心為DispatcherServlet.java與HandlerMapper。在spring boot初始化的時(shí)候,將會加載所有的請求與對應(yīng)的處理器映射為HandlerMapper組件。我們可以在springMVC的自動(dòng)配置類中找到對應(yīng)的Bean。
@Bean @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping( @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { // Must be @Primary for MvcUriComponentsBuilder to work return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider); } @Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping( new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), this.mvcProperties.getStaticPathPattern()); welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations()); return welcomePageHandlerMapping; }
請求將首先執(zhí)行FrameworkServlet
下的service方法根據(jù)request請求的method找到對應(yīng)的do**方法。
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null) { processRequest(request, response); } else { //父類根據(jù)method參數(shù)執(zhí)行doGet,doPost,doDelete等 super.service(request, response); } }
而這些do**其都會進(jìn)入核心方法,以doGet為例。
@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //核心方法 processRequest(request, response); }
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //進(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 { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); }
processRequest()
方法中重點(diǎn)在doService(request, response);
,而其核心處理邏輯位于DispatchServletl類重寫的方法,如下。
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ···· try { //這里為實(shí)際分發(fā)控制器的邏輯,其內(nèi)部是找到對應(yīng)的handlerMapper 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); } } if (requestPath != null) { ServletRequestPathUtils.clearParsedRequestPath(request); } } }
接下來看分發(fā)處理邏輯方法,其中重要的方法都使用了原生的注釋。接下來分別分析核心源碼。
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 (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); } } } }
首先是分析getHandler(),找到對應(yīng)的處理器映射邏輯。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
我們將斷點(diǎn)標(biāo)記在getHandler
方法上時(shí),可以清除看到handlerMappings
,如圖。
這里,用戶請求與處理器的映射關(guān)系都在RequestMapperHandlerMapping
中,而歡迎頁處理請求則在WelcomePageHanderMapping
中進(jìn)行映射。
以下為RequestMapperHandlerMapping中映射部分截圖,可以看到用戶的所有請求映射這里面都有:
getHandler()后的方法是通過比較request請求中method與HandlerMapper中相同url下的method,再進(jìn)行唯一性校驗(yàn),不通過異常,通過找到唯一的handler。
后續(xù),通過handler找到處理的設(shè)配器,通過適配器得到一個(gè)ModelAndView對象,這個(gè)對象就是最后返回給前端頁面的對象。
至此,一個(gè)請求完整映射到返回前端結(jié)束。
說明:這是實(shí)現(xiàn)了FramworkServlet的doService方法,F(xiàn)ramworkServlet繼承自HttpServlet,并且重寫了父類中的doGet(),doPost(),doPut(),doDelete 等方法,在這些重寫的方法里都調(diào)用了 processRquest() 方法做請求處理,進(jìn)入processRquest()可以看到里面調(diào)用了FramworkServlet中定義的doService() 方法。
上述就是小編為大家分享的使用SpringMVC請求怎么對handler進(jìn)行映射了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。