Java?spring?mvc請(qǐng)求詳情介紹
前言:
- 本文源碼基于
spring-framework-5.3.10
。 mvc
是spring
源碼中的一個(gè)子模塊!
一、源碼執(zhí)行流程
- 用戶發(fā)送請(qǐng)求至前端控制器DispatcherServlet。
DispatcherServlet
收到請(qǐng)求調(diào)用處理器映射器HandlerMapping
。處理器映射器根據(jù)請(qǐng)求url找到具體的處理器,生成處理器執(zhí)行鏈HandlerExecutionChain
(包括處理器對(duì)象和處理器攔截器)一并返回給DispatcherServlet。DispatcherServlet
根據(jù)處理器Handler獲取處理器適配器HandlerAdapter
,執(zhí)行HandlerAdapter處理一系列的操作,如:參數(shù)封裝,數(shù)據(jù)格式轉(zhuǎn)換,數(shù)據(jù)驗(yàn)證等操作- 執(zhí)行處理器Handler(Controller,也叫頁(yè)面控制器)。Handler執(zhí)行完成返回
ModelAndView
、HandlerAdapter
將Handler執(zhí)行結(jié)果ModelAndView返回到DispatcherServlet。 DispatcherServlet
將ModelAndView
傳給ViewReslover視圖解析器。ViewReslover解析后返回具體ViewDispatcherServlet
對(duì)View進(jìn)行渲染視圖(即將模型數(shù)據(jù)model填充至視圖中)。- DispatcherServlet響應(yīng)用戶。
二、源碼執(zhí)行流程圖
三、spring mvc中的一核心組件
- DispatcherServlet: 前端調(diào)度器 , 負(fù)責(zé)將請(qǐng)求攔截下來(lái)分發(fā)到各控制器方法中
- HandlerMapping: 負(fù)責(zé)根據(jù)請(qǐng)求的URL和配置@RequestMapping映射去匹配, 匹配到會(huì)返回Handler(具體控制器的方法)
- HandlerAdaper: 負(fù)責(zé)調(diào)用Handler-具體的方法- 返回視圖的名字 Handler將它封裝到ModelAndView(封裝視圖名,request域的數(shù)據(jù))
- ViewReslover: 根據(jù)ModelAndView里面的視圖名地址去找到具體的jsp封裝在View對(duì)象中
- View:進(jìn)行視圖渲染(將jsp轉(zhuǎn)換成html內(nèi)容 --這是Servlet容器的事情了) 最終response到的客戶端
四、源碼分析
/** * 最核心的控制器 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) */ 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 { // 驗(yàn)證是不是上傳的請(qǐng)求,上傳的請(qǐng)求會(huì)轉(zhuǎn)化為MultipartHttpServletRequest processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 進(jìn)行映射 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 找到最合適的HandlerAdapter,按照順序,那個(gè)先解析到就是那個(gè) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. HTTP緩存相關(guān) String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 前置攔截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 返回false就不進(jìn)行后續(xù)處理了 return; } // Actually invoke the handler. // 獲取參數(shù),執(zhí)行方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 如果mv有 視圖沒(méi)有,給你設(shè)置默認(rèn)視圖 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); } } } }
五、獲取組件相關(guān)邏輯:
原理:誰(shuí)先解析到就用誰(shuí)!
/** * 獲取處理器映射器 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest) */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { /** 拿到所有handlerMappings (容器啟動(dòng)階段初始化:拿到所有實(shí)現(xiàn)了HandlerMapping的Bean) * @see DispatcherServlet#initHandlerMappings * 測(cè)試發(fā)現(xiàn): 不同的HandlerMapping可以有相同path, 誰(shuí)先解析到就用哪個(gè) * */ for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; } /** * 獲取處理器適配器 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(Object) */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 按照配置的順序,誰(shuí)先解析到就用那個(gè) for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
六、獲取參數(shù),執(zhí)行方法源碼分析
/** * 獲取參數(shù),執(zhí)行方法最外層的調(diào)用 * 源碼位置:org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(HttpServletRequest, HttpServletResponse, Object) */ public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 直接調(diào)用這個(gè)方法 return handleInternal(request, response, (HandlerMethod) handler); } /** * 獲取參數(shù),執(zhí)行方法內(nèi)部的調(diào)用邏輯 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod) */ protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; // 檢查當(dāng)前請(qǐng)求的method是否為支持的method(默認(rèn)Null,可通過(guò)繼承AbstractController設(shè)置supportedMethods) // 檢查當(dāng)前請(qǐng)求是否必須session (默認(rèn)false,可通過(guò)繼承AbstractController設(shè)置requireSession) checkRequest(request); /** * 判斷當(dāng)前是否需要支持在同一個(gè)session中只能線性地處理請(qǐng)求:一個(gè)session同時(shí)只能處理一個(gè)線程 * 因?yàn)殒i是通過(guò) synchronized 是 JVM 進(jìn)程級(jí),所以在分布式環(huán)境下, * 無(wú)法達(dá)到同步相同 Session 的功能。默認(rèn)情況下,synchronizeOnSession 為 false */ if (this.synchronizeOnSession) { // 獲取當(dāng)前請(qǐng)求的session對(duì)象 HttpSession session = request.getSession(false); if (session != null) { // 為當(dāng)前session生成一個(gè)唯一的可以用于鎖定的key Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { // 對(duì)HandlerMethod進(jìn)行參數(shù)等的適配處理,并調(diào)用目標(biāo)handler mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // 如果當(dāng)前不存在session,則直接對(duì)HandlerMethod進(jìn)行適配 mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // *如果當(dāng)前不需要對(duì)session進(jìn)行同步處理,則直接對(duì)HandlerMethod進(jìn)行適配 mav = invokeHandlerMethod(request, response, handlerMethod); } //判斷當(dāng)前請(qǐng)求頭中是否包含Cache-Control請(qǐng)求頭,如果不包含,則對(duì)當(dāng)前response進(jìn)行處理 if (!response.containsHeader(HEADER_CACHE_CONTROL)) { // 如果當(dāng)前SessionAttribute中存在配置的attributes,則為其設(shè)置過(guò)期時(shí)間。 // 這里SessionAttribute主要是通過(guò)@SessionAttribute注解生成的 if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { // 如果當(dāng)前不存在SessionAttributes,則判斷當(dāng)前是否存在Cache-Control設(shè)置, // 如果存在,則按照該設(shè)置進(jìn)行response處理,如果不存在,則設(shè)置response中的 // Cache的過(guò)期時(shí)間為-1,即立即失效 prepareResponse(response); } } return mav; } /** * 獲取參數(shù),執(zhí)行方法前的準(zhǔn)備邏輯 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod) */ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { // 把我們的請(qǐng)求req resp包裝成 ServletWebRequest ServletWebRequest webRequest = new ServletWebRequest(request, response); try { // 獲取容器中全局配置的InitBinder和當(dāng)前HandlerMethod所對(duì)應(yīng)的Controller中 // 配置的InitBinder,用于進(jìn)行參數(shù)的綁定 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 獲取容器中全局配置的ModelAttribute和當(dāng)前HandlerMethod所對(duì)應(yīng)的Controller 中配置的ModelAttribute, // 這些配置的方法將會(huì)在目標(biāo)方法調(diào)用之前進(jìn)行調(diào)用 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 封裝handlerMethod,會(huì)在調(diào)用前解析參數(shù)、調(diào)用后對(duì)返回值進(jìn)行處理 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { // 讓invocableMethod擁有參數(shù)解析能力 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { // 讓invocableMethod擁有返回值處理能力 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } // 讓invocableMethod擁有InitBinder解析能力 invocableMethod.setDataBinderFactory(binderFactory); // 設(shè)置ParameterNameDiscoverer,該對(duì)象將按照一定的規(guī)則獲取當(dāng)前參數(shù)的名稱 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // ModelAndView處理容器 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 將request的Attribute復(fù)制一份到ModelMap mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // *調(diào)用我們標(biāo)注了@ModelAttribute的方法,主要是為我們的目標(biāo)方法預(yù)加載 modelFactory.initModel(webRequest, mavContainer, invocableMethod); // 重定向的時(shí)候,忽略model中的數(shù)據(jù) 默認(rèn)false mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // 獲取當(dāng)前的AsyncWebRequest,這里AsyncWebRequest的主要作用是用于判斷目標(biāo) // handler的返回值是否為WebAsyncTask或DeferredResult,如果是這兩種中的一種, // 則說(shuō)明當(dāng)前請(qǐng)求的處理應(yīng)該是異步的。所謂的異步,指的是當(dāng)前請(qǐng)求會(huì)將Controller中 // 封裝的業(yè)務(wù)邏輯放到一個(gè)線程池中進(jìn)行調(diào)用,待該調(diào)用有返回結(jié)果之后再返回到response中。 // 這種處理的優(yōu)點(diǎn)在于用于請(qǐng)求分發(fā)的線程能夠解放出來(lái),從而處理更多的請(qǐng)求,提高吞吐。 // 只有待目標(biāo)任務(wù)完成之后才會(huì)回來(lái)將該異步任務(wù)的結(jié)果返回。 AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); // 封裝異步任務(wù)的線程池、request、interceptors到WebAsyncManager中 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); // 這里就是用于判斷當(dāng)前請(qǐng)求是否有異步任務(wù)結(jié)果的,如果存在,則對(duì)異步任務(wù)結(jié)果進(jìn)行封裝 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 + "]"; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); } // *對(duì)請(qǐng)求參數(shù)進(jìn)行處理,調(diào)用目標(biāo)HandlerMethod,并且將返回值封裝為一個(gè)ModelAndView對(duì)象 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 對(duì)封裝的ModelAndView進(jìn)行處理,主要是判斷當(dāng)前請(qǐng)求是否進(jìn)行了重定向,如果進(jìn)行了重定向, // 還會(huì)判斷是否需要將FlashAttributes封裝到新的請(qǐng)求中 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } } /** * 獲取參數(shù),執(zhí)行方法 * 源碼位置:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...) */ public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { /*真正的調(diào)用我們的目標(biāo)對(duì)象 很重要 很重要*/ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 設(shè)置相關(guān)的返回狀態(tài) setResponseStatus(webRequest); // 如果請(qǐng)求處理完成,則設(shè)置requestHandled屬性 if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } // 如果請(qǐng)求失敗,但是有錯(cuò)誤原因,那么也會(huì)設(shè)置requestHandled屬性 else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { // 遍歷當(dāng)前容器中所有ReturnValueHandler,判斷哪種handler支持當(dāng)前返回值的處理, // 如果支持,則使用該handler處理該返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
七、渲染視圖邏輯
/** * 渲染視圖邏輯 * 源碼位置:org.springframework.web.servlet.DispatcherServlet.processDispatchResult(HttpServletRequest, HttpServletResponse, HandlerExecutionChain, ModelAndView, Exception) */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; // 異常視圖 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { // 解析、渲染視圖:解析視圖名,拼接前后綴 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. 攔截器:AfterCompletion mappedHandler.triggerAfterCompletion(request, response, null); } }
到此這篇關(guān)于Java spring mvc請(qǐng)求詳情介紹的文章就介紹到這了,更多相關(guān)spring mvc請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot全局配置long轉(zhuǎn)String丟失精度問(wèn)題解決方案
這篇文章主要介紹了SpringBoot全局配置long轉(zhuǎn)String丟失精度問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java基礎(chǔ)篇_有關(guān)接口和抽象類的幾道練習(xí)題(分享)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)篇_有關(guān)接口和抽象類的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例
這篇文章主要介紹了微信小程序調(diào)用微信登陸獲取openid及java做為服務(wù)端示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Spring Boot命令行啟動(dòng)添加參數(shù)的三種方式
在命令行中,常見(jiàn)的參數(shù)可以分為三類:選項(xiàng)參數(shù)、非選項(xiàng)參數(shù)和系統(tǒng)參數(shù),本文就來(lái)介紹一下Spring Boot命令行三種參數(shù)形式,感興趣的可以了解一下2023-09-09Mybatis-Plus中and()和or()的使用與原理詳解
最近發(fā)現(xiàn)MyBatisPlus還是挺好用的,下面這篇文章主要給大家介紹了關(guān)于Mybatis-Plus中and()和or()的使用與原理的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09java不同版本在多線程中使用隨機(jī)數(shù)生成器的實(shí)現(xiàn)
本文主要介紹了java不同版本在多線程中使用隨機(jī)數(shù)生成器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04