SpringMVC的介紹
【1】Spring Web MVC是基于Servlet API構建的原始Web框架,從一開始就已包含在Spring框架中,正式名稱“ Spring Web MVC”來自其源模塊的名稱(spring-webmvc),但它通常被稱為“ Spring MVC”,
SpringMVC的具體執行流程:
【1】說明:
1)Spring MVC 是圍繞前端控制器模式設計的,其中:中央 Servlet DispatcherServlet 為請求處理流程提供統一調度,實際作業則交給可配置組件執行,這個模型是靈活的且開放的,我們可以通過自己去定制這些組件從而進行定制自己的作業流,
2)說白了就是用一個DispatcherServlet 封裝了一個Servlet的調度中心, 由調度中心幫我們呼叫我們的處理方法:在這個程序中調度中心委托給各個組件執行具體作業 ,比如幫我們映射方法請求、幫我決議引數、呼叫處理方法、回應資料和頁面 等
【2】圖示:

【3】組件說明:
DispatcherServlet: 前端調度器 , 負責將請求攔截下來分發到各控制器方法中 HandlerMapping: 負責根據請求的URL和配置@RequestMapping映射去匹配, 匹配到會回傳Handler(具體控制器的方法) HandlerAdaper: 負責呼叫Handler-具體的方法- 回傳視圖的名字 Handler將它封裝到ModelAndView(封裝視圖名,request域的資料) ViewReslover: 根據ModelAndView里面的視圖名地址去找到具體的jsp封裝在View物件中 View:進行視圖渲染(將jsp轉換成html內容 --這是Servlet容器的事情了) 最終response到的客戶端
【4】流程說明:
1)用戶發送請求至前端控制器DispatcherServlet 2)DispatcherServlet收到請求呼叫處理器映射器HandlerMapping, 2.1)處理器映射器根據請求url找到具體的處理器,生成處理器執行鏈HandlerExecutionChain(包括處理器物件和處理器攔截器)一并回傳給DispatcherServlet, 3)DispatcherServlet根據處理器Handler獲取處理器配接器HandlerAdapter,執行HandlerAdapter處理一系列的操作,如:引數封裝,資料格式轉換,資料驗證等操作 4)執行處理器Handler(Controller,也叫頁面控制器), 4.1)Handler執行完成回傳ModelAndView 4.2)HandlerAdapter將Handler執行結果ModelAndView回傳到DispatcherServlet 5)DispatcherServlet將ModelAndView傳給ViewReslover視圖決議器 5.1)ViewReslover決議后回傳具體View 6)DispatcherServlet對View進行渲染視圖(即將模型資料model填充至視圖中), 7)DispatcherServlet回應用戶,
SpringMVC請求流程圖解:

執行流程原始碼決議(我是直接開啟SpringBoot里面分析的)
【1】分析主線流程,DispatcherServlet類#doDispatch方法
//DispatcherServlet類#doDispatch方法 //主流程1,執行DispatcherServlet類#doDispatch方法 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 { //檢查請求是否是multipart(即檔案上傳),若是進行相關處理 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); //通過handermapping映射獲取HandlerExecutionChain(處理鏈中包括了interceptor的前置和后置方法) //主流程2,獲取HandlerExecutionChain mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 根據處理器(handler及HandlerExecutionChain)獲取處理器配接器(處理器配接器是為了提供統一介面進行后續處理,從而支持多種型別的處理器)
// 主流程3的具體地方 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. 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; } } //執行chain中攔截器附加的預處理方法,即preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 回傳false就不進行后續處理了 return; } // 執行HandlerAdapter處理一系列的操作,如:引數封裝,資料格式轉換,資料驗證等操作 ,主流程4的具體地方 // 執行處理器Handler(Controller,也叫頁面控制器), // Handler執行完成回傳ModelAndView // HandlerAdapter將Handler執行結果ModelAndView回傳到DispatcherServlet mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 如果沒有視圖,給你設定默認視圖 json忽略 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); } // DispatcherServlet將ModelAndView傳給ViewReslover視圖決議器 // ViewReslover決議后回傳具體View // DispatcherServlet對View進行渲染視圖(即將模型資料model填充至視圖中), // DispatcherServlet回應用戶, // 如果有例外,還會處理例外 ,主流程5,6的具體地方 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //攔截器afterCompletion處理器 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); } } } }
【2】分析getHandler方法如何回傳 處理器執行鏈HandlerExecutionChain:
//分析getHandler //this.handlerMappings的內容 //0.RequestMappingHandlerMapping //1.BeanNameUrlHandlerMapping //2.RouterFunctionMapping //3.SimpleUrlHandlerMapping //4.WelcomePageHandlerMapping @Nullable 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; } //呼叫到了AbstractHandlerMapping類#getHandler方法 @Override @Nullable public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //getHandlerInternal(request)方法為抽象方法,供子類實作 //獲取到的handler物件一般為bean/HandlerMethod Object handler = getHandlerInternal(request); //上述找不到則使用默認的處理類,沒有設定則回傳null,則會回傳前臺404錯誤 if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // Ensure presence of cached lookupPath for interceptors and others if (!ServletRequestPathUtils.hasCachedPath(request)) { initLookupPath(request); } //創建處理鏈物件 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); //針對cros跨域請求的處理 if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) { CorsConfiguration config = getCorsConfiguration(handler, request); if (getCorsConfigurationSource() != null) { CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request); config = (globalConfig != null ? globalConfig.combine(config) : config); } if (config != null) { config.validateAllowCredentials(); } executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
【2.1】分析AbstractHandlerMapping類#getHandler方法
【2.1.1】如何獲取handler物件【一般為bean/HandlerMethod】
//RequestMappingInfoHandlerMapping類#getHandlerInternal方法 //因為它是RequestMappingHandlerMapping的父類 @Override @Nullable protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); try { //呼叫父類AbstractHandlerMethodMapping類 return super.getHandlerInternal(request); } finally { ProducesRequestCondition.clearMediaTypesAttribute(request); } } //呼叫到AbstractHandlerMethodMapping類getHandlerInternal方法 //針對HandlerMethod的獲取 protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //獲取訪問的路徑,一般類似于request.getServletPath()回傳不含contextPath的訪問路徑 String lookupPath = initLookupPath(request); //獲取讀鎖 this.mappingRegistry.acquireReadLock(); try { //獲取HandlerMethod作為handler物件,這里涉及到路徑匹配的優先級 //優先級:精確匹配>最長路徑匹配>擴展名匹配 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); //HandlerMethod內部含有bean物件,其實指的是對應的Controller return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { //釋放讀鎖 this.mappingRegistry.releaseReadLock(); } }
【2.1.2】如何創建處理鏈
//創建處理器鏈的方法 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { /創建HandlerExecutionChain HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); //與請求url進行匹配,滿足的才加入 for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
【3】分析getHandlerAdapter尋找的處理器配接器
//分析getHandlerAdapter //this.handlerAdapters的內容 //0.RequestMappingHandlerAdapter //1.HandlerFunctionAdapter //2.HttpRequestHandlerAdapter //3.SimpleControllerHandlerAdapter protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { //所以一般回傳的也就是RequestMappingHandlerAdapter return adapter; } } } throw new ServletException(...); } //因為RequestMappingHandlerAdapter沒有重寫故呼叫父類的 //呼叫AbstractHandlerMethodAdapter類#supports方法 @Override public final boolean supports(Object handler) { //如果是類的方法的話默認是true return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); }
【4】分析mappedHandler.applyPreHandle前置處理器與mappedHandler.applyPostHandle后置處理器
//分析mappedHandler.applyPreHandle前置處理器與mappedHandler.applyPostHandle后置處理器 //前置處理器是從0到size boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for (int i = 0; i < this.interceptorList.size(); i++) { HandlerInterceptor interceptor = this.interceptorList.get(i); if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } return true; } //前置處理器是從size到0 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for (int i = this.interceptorList.size() - 1; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } }
【5】分析ha.handle(processedRequest, response, mappedHandler.getHandler());,如何進行呼叫控制器里面的方法
//AbstractHandlerMethodAdapter類#handle方法 //因為配接器RequestMappingHandlerAdapter類沒有所以定位到了父類 public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } //RequestMappingHandlerAdapter類#handleInternal方法 @Override protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; // 檢查當前請求的method是否為支持的method(默認Null,可通過繼承AbstractController設定supportedMethods) // 檢查當前請求是否必須session (默認false,可通過繼承AbstractController設定requireSession) checkRequest(request); /** * 判斷當前是否需要支持在同一個session中只能線性地處理請求 * 因為鎖是通過 synchronized 是 JVM 行程級,所以在分布式環境下, * 無法達到同步相同 Session 的功能,默認情況下,synchronizeOnSession 為 false */ if (this.synchronizeOnSession) { // 獲取當前請求的session物件 HttpSession session = request.getSession(false); if (session != null) { // 為當前session生成一個唯一的可以用于鎖定的key Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { // 對HandlerMethod進行引數等的適配處理,并呼叫目標handler mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // 如果當前不存在session,則直接對HandlerMethod進行適配 mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // 這般都會走這里,重點反射呼叫 // 如果當前不需要對session進行同步處理,則直接對HandlerMethod進行適配 mav = invokeHandlerMethod(request, response, handlerMethod); } //判斷當前請求頭中是否包含Cache-Control請求頭,如果不包含,則對當前response進行處理 if (!response.containsHeader(HEADER_CACHE_CONTROL)) { // 如果當前SessionAttribute中存在配置的attributes,則為其設定過期時間, // 這里SessionAttribute主要是通過@SessionAttribute注解生成的 if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { // 如果當前不存在SessionAttributes,則判斷當前是否存在Cache-Control設定, // 如果存在,則按照該設定進行response處理,如果不存在,則設定response中的 // Cache的過期時間為-1,即立即失效 prepareResponse(response); } } return mav; }
【5.1】分析invokeHandlerMethod方法怎么做【先是引數處理器,再是生成容器,然后去反射呼叫,最后將結果放入容器】
@Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { // 把我們的請求req resp包裝成 ServletWebRequest ServletWebRequest webRequest = new ServletWebRequest(request, response); try { // 獲取容器中全域配置的InitBinder和當前HandlerMethod所對應的Controller中 // 配置的InitBinder,用于進行引數的系結 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 獲取容器中全域配置的ModelAttribute和當前HandlerMethod所對應的Controller 中配置的ModelAttribute, // 這些配置的方法將會在目標方法呼叫之前進行呼叫 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 封裝handlerMethod,會在呼叫前決議引數、呼叫后對回傳值進行處理 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { // 讓invocableMethod擁有引數決議能力 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { // 讓invocableMethod擁有回傳值處理能力 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } // 讓invocableMethod擁有InitBinder決議能力 invocableMethod.setDataBinderFactory(binderFactory); // 設定ParameterNameDiscoverer,該物件將按照一定的規則獲取當前引數的名稱 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 創建ModelAndView處理容器 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); // 將request的Attribute復制一份到ModelMap mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // 呼叫我們標注了@ModelAttribute的方法,主要是為我們的目標方法預加載 modelFactory.initModel(webRequest, mavContainer, invocableMethod); // 重定向的時候,忽略model中的資料 默認false mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // 獲取當前的AsyncWebRequest,這里AsyncWebRequest的主要作用是用于判斷目標 // handler的回傳值是否為WebAsyncTask或DeferredResult,如果是這兩種中的一種, // 則說明當前請求的處理應該是異步的,所謂的異步,指的是當前請求會將Controller中 // 封裝的業務邏輯放到一個執行緒池中進行呼叫,待該呼叫有回傳結果之后再回傳到response中, // 這種處理的優點在于用于請求分發的執行緒能夠解放出來,從而處理更多的請求,提高吞吐, // 只有待目標任務完成之后才會回來將該異步任務的結果回傳, AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); // 封裝異步任務的執行緒池、request、interceptors到WebAsyncManager中 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); // 這里就是用于判斷當前請求是否有異步任務結果的,如果存在,則對異步任務結果進行封裝 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); } // 對請求引數進行處理,呼叫目標HandlerMethod,并且將回傳值封裝為一個ModelAndView物件 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 對封裝的ModelAndView進行處理,主要是判斷當前請求是否進行了重定向,如果進行了重定向,還會判斷是否需要將FlashAttributes封裝到新的請求中 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
【5.1.1】分析invocableMethod.invokeAndHandle怎么反射呼叫
//ServletInvocableHandlerMethod類#invokeAndHandle方法 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 真正的呼叫我們的目標物件 Object returnValue =https://www.cnblogs.com/chafry/archive/2022/10/31/ invokeForRequest(webRequest, mavContainer, providedArgs); // 設定相關的回傳狀態 setResponseStatus(webRequest); // 如果請求處理完成,則設定requestHandled屬性 if (returnValue =https://www.cnblogs.com/chafry/archive/2022/10/31/= null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } // 如果請求失敗,但是有錯誤原因,那么也會設定requestHandled屬性 else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { // 遍歷當前容器中所有ReturnValueHandler,判斷哪種handler支持當前回傳值的處理, // 如果支持,則使用該handler處理該回傳值 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { throw ex; } } //InvocableHandlerMethod類#invokeForRequest方法 public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 獲取我們目標方法入參的值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); // 反射呼叫 ,里面主要就是 method.invoke(getBean(), args) 來進行反射呼叫 return doInvoke(args); }
【5.1.2】分析 對封裝的ModelAndView進行處理
//RequestMappingHandlerAdapter類#getModelAndView方法 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }
【6】分析processDispatchResult方法對回傳結果的處理
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 (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled..
// 攔截器的后置處理 mappedHandler.triggerAfterCompletion(request, response, null); } }
【6.1】分析render方法視圖渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // 決議視圖名 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException(...); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException(...); } } // Delegate to the View object for rendering. try { if (mv.getStatus() != null) { request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus()); response.setStatus(mv.getStatus().value()); } // 進行視圖渲染 ,呼叫的是 AbstractView類的方法 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { throw ex; } }
原始碼決議注解@RequestMapping
【1】@RequestMapping決議
【1.1】說明:
1)明確一點:@RequestMapping是通過RequestMappingHandlerMapping負責決議,
2)HandlerMapping便是負責根據請求URI 映射 到對應的handler方法,而RequestMappingHandlerMapping是HandlerMapping的其中一個實作類, 負責根據@RequestMapping注解進行映射,
3)所以HandlerMapping有很多其他實作類,RequestMappingHandlerMapping是最常用的,HandlerMapping可分為2個程序:1決議、2映射
【1.2】分析RequestMappingHandlerMapping類
1)基于繼承關系可以發現它實作了InitializingBean介面
2)分析afterPropertiesSet方法做了什么
@Override @SuppressWarnings("deprecation") public void afterPropertiesSet() { //這里都是一些設定配置 this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setTrailingSlashMatch(useTrailingSlashMatch()); this.config.setContentNegotiationManager(getContentNegotiationManager()); if (getPatternParser() != null) { this.config.setPatternParser(getPatternParser()); } else { this.config.setSuffixPatternMatch(useSuffixPatternMatch()); this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch()); this.config.setPathMatcher(getPathMatcher()); } //呼叫父類AbstractHandlerMethodMapping類的afterPropertiesSet方法 super.afterPropertiesSet(); } //父類AbstractHandlerMethodMapping類的afterPropertiesSet方法 public void afterPropertiesSet() { initHandlerMethods(); } //AbstractHandlerMethodMapping類#initHandlerMethods方法 protected void initHandlerMethods() { // 獲得所有候選beanName—— 當前容器所有的beanName for (String beanName : getCandidateBeanNames()) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { // 處理候選bean——即決議@RequestMapping和映射路徑 processCandidateBean(beanName); } } // 決議完所有@RequestMapping的時候呼叫,輸出日志 handlerMethodsInitialized(getHandlerMethods()); }
【1.2.1】分析processCandidateBean方法怎么處理的
protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) {..省略日志..} // 這一步判斷是關鍵 是否有Controller 或 RequestMapping注解 if (beanType != null && isHandler(beanType)) { // 決議HandlerMethods detectHandlerMethods(beanName); } } protected void detectHandlerMethods(Object handler) { Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { Class<?> userType = ClassUtils.getUserClass(handlerType); // 回圈所有方法 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { return getMappingForMethod(method, userType); } catch (Throwable ex) {..省略例外..} }); ..省略日志.. //回圈注冊 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } }
【1.2.1.1】決議流程
//呼叫回子類RequestMappingHandlerMapping類#getMappingForMethod方法 protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 如果方法上面有@RequestMapping:決議出RequestMappingInfo // RequestMappingInfo 是用來在請求的時候做匹對的 RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { // 如果方法上面有@RequestMapping,看看類上面是不是有@RequestMapping RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); // 類上面也有@RequestMapping 那就合并 // 比如 類:/user 方法:/info 合并為 /user/info if (typeInfo != null) { info = typeInfo.combine(info); } // 合并前綴 5.1新增 默認null // 可通過 WebMvcConfigurer#configurePathMatch 進行定制 String prefix = getPathPrefix(handlerType); if (prefix != null) { info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info); } } return info; }
【1.2.1.2】注冊流程
//呼叫回子類RequestMappingHandlerMapping類#registerHandlerMethod方法 protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) { super.registerHandlerMethod(handler, method, mapping); updateConsumesCondition(mapping, method); } //父類AbstractHandlerMethodMapping類#registerHandlerMethod方法 //其中private final MappingRegistry mappingRegistry = new MappingRegistry(); protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } //兩大存盤容器 //private final Map<T, MappingRegistration<T>> registry = new HashMap<>(); //private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>(); //pathLookup存盤【path, mapping】 //registry存盤【mapping,與之對應的【mapping, handlerMethod, directPaths, name, corsConfig】】 public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); validateMethodMapping(handlerMethod, mapping); Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping); for (String path : directPaths) { this.pathLookup.add(path, mapping); } String name = null; if (getNamingStrategy() != null) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { corsConfig.validateAllowCredentials(); this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null)); } finally { this.readWriteLock.writeLock().unlock(); } }
【2】@RequestMapping請求映射
【2.1】回看執行流程的【2.1.1】中的getHandlerInternal方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 通過UrlPathHelper物件,用于來決議從們的request中決議出請求映射路徑 String lookupPath = initLookupPath(request); //獲取讀鎖 this.mappingRegistry.acquireReadLock(); try { // 通過lookupPath決議最終的handler——HandlerMethod物件 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { //釋放讀鎖 this.mappingRegistry.releaseReadLock(); } } //分析查找流程 //先從pathLookup里面拿 //拿不到再去進行通配符匹配,排序獲取第一個最優匹配的 protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<>(); // 根據uri從mappingRegistry.pathLookup獲取 RequestMappingInfo // pathLookup<path,RequestMappingInfo>會在初始化階段決議好 List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null) { // 如果根據path能直接匹配的RequestMappingInfo 則用該mapping進行匹配其他條件(method、header等) addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // 如果無path匹配,用所有的RequestMappingInfo 通過AntPathMatcher匹配 addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request); } if (!matches.isEmpty()) { // 選擇第一個為最匹配的 Match bestMatch = matches.get(0); /** * 如果匹配到多個 @RequestMapping(value="https://www.cnblogs.com/mappin?") @RequestMapping(value="https://www.cnblogs.com/mappin*") @RequestMapping(value="https://www.cnblogs.com/{xxxx}") @RequestMapping(value="https://www.cnblogs.com/**") */ if (matches.size() > 1) { //創建MatchComparator的匹配器物件 Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); /** 根據精準度排序 大概是這樣的: ? > * > {} >** 具體可以去看: * @see org.springframework.util.AntPathMatcher.AntPatternComparator#compare(java.lang.String, java.lang.String)*/ matches.sort(comparator); // 排完序后拿到優先級最高的 bestMatch = matches.get(0); // 是否配置CORS并且匹配 if (CorsUtils.isPreFlightRequest(request)) { for (Match match : matches) { if (match.hasCorsConfig()) { return PREFLIGHT_AMBIGUOUS_MATCH; } } } else { //獲取第二最匹配的 Match secondBestMatch = matches.get(1); //若第一個和第二個是一樣的 拋出例外 if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.getHandlerMethod().getMethod(); Method m2 = secondBestMatch.getHandlerMethod().getMethod(); String uri = request.getRequestURI(); throw new IllegalStateException(...); } } } //把最匹配的設定到request中 request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod()); handleMatch(bestMatch.mapping, lookupPath, request); //回傳最匹配的 return bestMatch.getHandlerMethod(); } else { // return null return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request); } }
【2.1】期待后面繼續補充吧
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/523877.html
標籤:其他
