摘要:概述上一節我們分析了的初始化過程,即創建并注冊,本章我們分析下的請求處理過程,即查找。本系列文章是基于。最后創建了群方便大家交流,可掃描加入,同時也可加我,共同學習共同進步,謝謝
概述
上一節我們分析了RequestMappingHandlerMapping的初始化過程,即創建并注冊HandlerMehtod,本章我們分析下RequestMappingHandlerMapping的請求處理過程,即查找HandlerMethod。
本系列文章是基于Spring5.0.5RELEASE。
總體流程因本節重點分析RequestMappingHandlerMapping處理請求方式,所以我們從請求到達前端控制器(DispatcherServlet)的doDispatch方法開始,之前的請求處理可參考https://segmentfault.com/a/1190000014712270
流程描述:
用戶請求到達前端控制器DispatcherServlet.doDispatch方法
在doDispatch方法中調用本類的getHandler方法
getHandler方法調用HandlerMapping的getHandler方法
HandlerMapping.getHandler方法由抽象類AbstractHandlerMapping實現,故最終調用AbstracthandlerMapping.getHandler方法
在AbstractHandlerMapping的getHandler方法中調用鉤子函數getHandlerInternal方法,該方法由子類AbstractHandlerMethodMapping實現
最終由AbstracthandlerMethodMapping.getHandlerInternal返回處理器方法即HandlerMethod
HandlerMethod代表查找到的處理請求Controller中的方法
返回給AbstractHandlerMapping,最終由其將處理器方法和攔截器組裝成HandlerExectionChain對象返回
源碼分析DispatcherServlet
處理用戶請求的方法到達doDispatch方法,源碼如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // ... ... //查找請求的處理器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { // 未找到處理器時跑異常 noHandlerFound(processedRequest, response); return; } // ... ... } @Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // 迭代Spring支持的HandlerMapping,即我們配置或默認的HandlerMapping for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name "" + getServletName() + """); } // 查找請求的處理器HandlerExecutionChain,包括請求需要的攔截器 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } } return null; }
AbstractHandlerMethodMapping
提供查出處理器模板方法,具體實現由子類實現getHandlerInternal方法實現,代碼如下:
@Override @Nullable public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 子類需實現getHandlerInternal方法,本例中由AbstractHandlerMethodMapping實現 Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // 如果handler是bean名字,則根據名字從上下文獲取到處理類 if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } // 返回請求處理的HandlerExecutionChain對象 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // 對跨域的處理 if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
AbstractHandlerMethodMapping
本類主要提供創建并注冊HandlerMethod以及查找HandlerMethod功能,處理用戶請求時,源碼如下:
/** * 實現父類(AbstractHandlerMapping)的鉤子函數 */ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 使用工具類UrlPathHelper,解析用戶請求url String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } this.mappingRegistry.acquireReadLock(); try { // 查找HandlerMethod核心方法 HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } } /** * 查找當前請求的處理器方法 */ @Nullable protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { // 定義匹配到的matches集合,其內存放匹配到的Match對象 List總結matches = new ArrayList<>(); // 根據請求url查找出RequestMappingInfo對象 List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { // 將查找到的RequestMappingInfo和處理器方法封裝成Match對象存入到matches數組 addMatchingMappings(directPathMatches, matches, request); } // 為查詢到RequestMappingInfo時 if (matches.isEmpty()) { // this.mappingRegistry.getMappings().keySet()--返回已注冊所有的RequestMappingInfo // 查找到將RequestMappingInfo和處理器方法封裝后存入matches數組 addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } // 有匹配對象 if (!matches.isEmpty()) { // 排序處理 Comparator comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } // 取出Match,其封裝了RequestMappingInfo和處理器方法 Match bestMatch = matches.get(0); if (matches.size() > 1) { if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path "" + request.getRequestURL() + "": {" + m1 + ", " + m2 + "}"); } } // 主要是往Request的Attribute區放了些東西,具體啥用我也不懂 handleMatch(bestMatch.mapping, lookupPath, request); // 返回處理器方法HandlerMethod return bestMatch.handlerMethod; } else { // 未找到處理 return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } }
本節對RequestMappingHandlerMapping處理用戶請求時的整體流程及核心源碼進行了分析,如有問題或建議大家可掃描下方二維碼進群反饋,我會知無不言言無不盡,希望對大家有所幫助。
最后創建了qq群方便大家交流,可掃描加入,同時也可加我qq:276420284,共同學習、共同進步,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69516.html
摘要:接口接口作用是將請求映射到處理程序,以及預處理和處理后的攔截器列表,映射是基于一些標準的,其中的細節因不同的實現而不相同。該參數是類型,作用是檢查所有的映射解析器或使用或為的,默認為,即從上下文中檢查所有的。 概述 在Spring MVC啟動章節https://segmentfault.com/a/1190000014674239,介紹到了DispatcherServlet的onRef...
摘要:概述通過前三章的分析,我們簡要分析了和,但對攔截器部分做詳細的分析,攔截器的加載和初始化是三個相同的部分。 概述 通過前三章的分析,我們簡要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但對攔截器部分做詳細的分析,攔截器的加載和初始化是三個HandlerMapping相...
摘要:與類圖對比,類繼承自抽象類,其又繼承自抽象類,再往上繼承關系與一致。創建初始化上一章我們分析了的創建初始化過程,的創建初始化過程與一樣,方法的入口在抽象類中的方法。至此,代碼編寫完畢。 概述 本節我們繼續分析HandlerMapping另一個實現類BeanNameUrlHandlerMapping,從類的名字可知,該類會根據請求的url與spring容器中定義的bean的name屬性值...
摘要:由于抽象類重寫了父類的方法,所以此時會調用的方法,在該方法中通過調用父類的方法,該方法通過模板方法模式最終調到類的方法。分析該類間接實現了接口,直接實現該接口的是抽象類,映射與請求。 概述 在前一章https://segmentfault.com/a/1190000014901736的基礎上繼續分析,主要完成SimpleUrlHandlerMapping類的原理。 本系列文章是基于Sp...
摘要:默認支持該策略。以上是對的宏觀分析,下面我們進行內部細節分析。整體流程一通過實現接口,完成攔截器相關組件的初始化調用類的方法。總結本文主要分析了的初始化過程,希望對大家有幫助。隨著學習的深入,后面有時間在分析下期中涉及的關鍵,比如等等。 概述 本節我們繼續分析HandlerMapping另一個實現類ReqeustMappingHandlerMapping,該類是我們日常開發中使用最多的...
閱讀 1360·2021-11-24 09:39
閱讀 1351·2021-11-04 16:12
閱讀 2694·2021-09-24 09:47
閱讀 3341·2021-09-01 10:50
閱讀 1481·2019-08-30 15:55
閱讀 1427·2019-08-30 15:43
閱讀 648·2019-08-30 11:08
閱讀 3585·2019-08-23 18:33