摘要:默認支持該策略。以上是對的宏觀分析,下面我們進行內部細節分析。整體流程一通過實現接口,完成攔截器相關組件的初始化調用類的方法。總結本文主要分析了的初始化過程,希望對大家有幫助。隨著學習的深入,后面有時間在分析下期中涉及的關鍵,比如等等。
概述
本節我們繼續分析HandlerMapping另一個實現類ReqeustMappingHandlerMapping,該類是我們日常開發中使用最多的映射器策略,即我們在開發中使用的注解開發方式,如:@Controller、@RequestMapping等,都使用的是此映射策略。Spring MVC默認支持該策略。
本系列文章是基于Spring5.0.5RELEASE。
類圖類的繼承關系,如下圖:
第一次看到此圖可能會感覺好復雜,大家別急,學技術就是這樣,首先需要靜下心,再一個要學會對已掌握知識點做總結、對比、分類,這樣才能把所有的知識點串起來,能系統的了解一項技術。
以上是我個人的一些經驗,希望對別人能有幫助,廢話不多說了,我們來分析下這張圖,之前我們學過了SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping,通過橫向對比,我們發現,他們都繼承自AbstractHandlerMapping抽象類,而AbstractHandlerMapping類的主要工作就是初始化攔截器的功能,三者的實現都是一樣的。
繼續分析,我們發現RequestMappingHandlerMapping增加實現了InitializingBean和EmbeddedVualeResolverAware接口,即增加了如下能力:
實現InitializingBean接口,增加了bean初始化的能力,也就是說在bean初始化時可以做一些控制
實現EmbeddedValueResolverAware接口,即增加了讀取屬性文件的能力
這兩個接口都是Spring自動幫我們調用其中的方法的。也就是說,RequestMappingHandlerMapping通過這些能力來完成初始化HandlerMapping接口的。
以上是對RequestMappingHandlerMapping的宏觀分析,下面我們進行內部細節分析。
整體流程一、通過實現ApplicationContextAware接口,完成攔截器相關組件的初始化
調用AbstractHandlerMapping類的initApplicationContext()方法。//TODO 下節分析
二、通過實現InitializingBean接口,完成url與處理器方法的映射(url->RequestMappingInfo,RequstMappingInfo->HandlerMehtod)
調用RequestMappingHandlerMapping類實現的afterPropertiesSet()方法,通過該方法最終調到其父類的initHandlerMethods()方法,這個方法是完成映射解析工作:
1、獲取上下文環境中所有的bean
2、迭代所有的bean,通過isHandler方法判斷是否是handler
2.1 調用RequestMappingHandlerMapping.isHandler方法,根據@Controller或@RequestMapping注解判斷(“或”關系,任意一個)3、解析出handler中所有需要處理的方法,即標注了@RequestMapping注解的方法,封裝在detectHandlerMehtods方法中
3.1 獲取到原始的Class>
3.2 使用MethodIntrospector.selectMethods方法過濾具體的handler method,通過模板方法模式getMappingForMethod預留給子類
RequestMappingHandlerMapping.getMappingForMehtod方法,通過方法、類上面@RequestMapping注解生成匹配條件RequestMappingInfo對象
3.3 對過濾到的每個method進行注冊,通過registerHandlerMehtod方法完成
通過createHandlerMethod方法創建HandlerMethod對象來封裝處理器方法
判斷匹配條件與處理器是否沖突,即同一個匹配條件只能對應一個處理器方法
把匹配條件與處理器方法存入map
從匹配條件中解析出url,通過RequestMappingInfoHandlerMapping.getMappingPathPatterns方法實現,之后把url與匹配條件存入另一個map
4、對HandlerMethod進行初始化,調用handlerMethodsInitialized方法,其內部什么都沒做
以上是初始化RequestMappingHandlerMapping的整體流程。
源碼分析AbstractHandlerMapping
初始化攔截器
// 初始化攔截器,即初始化url需要的攔截器 @Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.adaptedInterceptors); initInterceptors(); }
AbstractHandlerMethodMapping
控制初始化RequestMappingHandlerMapping.initHanderMethods方法整體流程,代碼如下:
/** * 在ApplicationContext上下文掃描所有的bean,檢測和注冊處理器方法(handler method) */ protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } // 從上下文中查找所有的bean String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class)); // 遍歷所有的beanName for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class> beanType = null; try { // 獲得bean的類型 beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let"s ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name "" + beanName + """, ex); } } // 判斷類是否被@Controller或是@RequestMapping注釋 // isHandler方法由子類RequestMappingHandlerMapping去實現 if (beanType != null && isHandler(beanType)) { // 注冊url與處理器方法的關系 detectHandlerMethods(beanName); } } } // 空方法 handlerMethodsInitialized(getHandlerMethods()); } /** * 查找處理程序handler中的處理方法 */ protected void detectHandlerMethods(final Object handler) { // 獲取handler的類型 Class> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { // 獲取給定類的用戶定義類型,通常為給定類的類型,但在cglib生成子類的情況下,返回的是原始類型 final Class> userType = ClassUtils.getUserClass(handlerType); // 獲取處理器方法map,key是Method,value是匹配條件RequestMappingInfo對象 // map中不包括未被@RequestMapping注解的方法 Mapmethods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup ) method -> { try { // 調用子類RequestMappingHandlerMapping的getMappingForMethod方法進行處理,即根據RequestMapping注解信息創建匹配條件RequestMappingInfo對象 return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } // 遍歷map,獲得Method和RequestMappingInfo,注冊他們 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); // 調用本類registerHandlerMethod()方法 registerHandlerMethod(handler, invocableMethod, mapping); }); } } /** * 注冊rul和處理器方法的映射關系 */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { // 調用內部類MappingRegistry的register()方法 this.mappingRegistry.register(mapping, handler, method); } /** * 此方法是內部類MappingRegistry的方法 */ public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { // 創建處理器方法HandlerMethod實例,即Controller中的處理方法 HandlerMethod handlerMethod = createHandlerMethod(handler, method); // 判斷匹配條件是否重復,即一個@RequestMapping的映射url只能對應一個方法 assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info("Mapped "" + mapping + "" onto " + handlerMethod); } // 將匹配條件RequestMappingInfo和處理器方法保存到map中 this.mappingLookup.put(mapping, handlerMethod); // 獲得url映射路徑,將映射路徑和匹配條件對象RequestMappingInfo存起來 // 調用本類的getDerectUrls方法 List directUrls = getDirectUrls(mapping); for (String url : directUrls) { this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } // 將映射注冊對象存入map this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } private List getDirectUrls(T mapping) { List urls = new ArrayList<>(1); // 調用子類RequestMappingInfoHandlerMapping.getMappingPathPatterns方法 for (String path : getMappingPathPatterns(mapping)) { if (!getPathMatcher().isPattern(path)) { urls.add(path); } } return urls; }
RequestMappingHandlerMapping
根據@RequestMapping生成RequestMappingInfo對象,主要代碼如下:
/** * 使用方法和類型注解@RequestMapping創建RequestMappingInfo對象 */ @Override @Nullable protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) { // 創建方法的RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { // 創建類的RequestMappingInfo RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { // 將方法RequestMappingInfo和類RequestMappingInfo合并,比如Controller類上有@RequestMapping("/demo"),方法的@RequestMapping("/demo1"),結果為"/demo/demo1" info = typeInfo.combine(info); } } return info; } @Nullable private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { // 獲取RequestMapping注解 RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition> condition = (element instanceof Class ? getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element)); // 調用createRequestMappingInfo創建匹配條件對象 return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); } /** * 構造匹配條件對象 */ protected RequestMappingInfo createRequestMappingInfo( RequestMapping requestMapping, @Nullable RequestCondition> customCondition) { RequestMappingInfo.Builder builder = RequestMappingInfo .paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) .methods(requestMapping.method()) .params(requestMapping.params()) .headers(requestMapping.headers()) .consumes(requestMapping.consumes()) .produces(requestMapping.produces()) .mappingName(requestMapping.name()); if (customCondition != null) { builder.customCondition(customCondition); } return builder.options(this.config).build(); }
RequestMappingInfoHandlerMapping
提供匹配條件RequestMappingInfo的解析處理,涉及的代碼如下:
/** * 獲取url集合,即@RequestMapping中設置的value或path */ @Override protected SetgetMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }
以上即RequestMappingHandlerMapping對象的初始化過程及初始化過程的核心源碼。
總結本文主要分析了RequestMappingHandlerMapping的初始化過程,希望對大家有幫助。隨著學習的深入,后面有時間在分析下期中涉及的關鍵bean,比如:RequestMappingInfo、RequestCondition、HandlerMethod等等。大家加油!
最后創建了qq群方便大家交流,可掃描加入,同時也可加我qq:276420284,共同學習、共同進步,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69487.html
摘要:接口接口作用是將請求映射到處理程序,以及預處理和處理后的攔截器列表,映射是基于一些標準的,其中的細節因不同的實現而不相同。該參數是類型,作用是檢查所有的映射解析器或使用或為的,默認為,即從上下文中檢查所有的。 概述 在Spring MVC啟動章節https://segmentfault.com/a/1190000014674239,介紹到了DispatcherServlet的onRef...
摘要:概述通過前三章的分析,我們簡要分析了和,但對攔截器部分做詳細的分析,攔截器的加載和初始化是三個相同的部分。 概述 通過前三章的分析,我們簡要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但對攔截器部分做詳細的分析,攔截器的加載和初始化是三個HandlerMapping相...
摘要:與類圖對比,類繼承自抽象類,其又繼承自抽象類,再往上繼承關系與一致。創建初始化上一章我們分析了的創建初始化過程,的創建初始化過程與一樣,方法的入口在抽象類中的方法。至此,代碼編寫完畢。 概述 本節我們繼續分析HandlerMapping另一個實現類BeanNameUrlHandlerMapping,從類的名字可知,該類會根據請求的url與spring容器中定義的bean的name屬性值...
摘要:概述上一節我們分析了的初始化過程,即創建并注冊,本章我們分析下的請求處理過程,即查找。本系列文章是基于。最后創建了群方便大家交流,可掃描加入,同時也可加我,共同學習共同進步,謝謝 概述 上一節我們分析了RequestMappingHandlerMapping的初始化過程,即創建并注冊HandlerMehtod,本章我們分析下RequestMappingHandlerMapping的請求...
摘要:由于抽象類重寫了父類的方法,所以此時會調用的方法,在該方法中通過調用父類的方法,該方法通過模板方法模式最終調到類的方法。分析該類間接實現了接口,直接實現該接口的是抽象類,映射與請求。 概述 在前一章https://segmentfault.com/a/1190000014901736的基礎上繼續分析,主要完成SimpleUrlHandlerMapping類的原理。 本系列文章是基于Sp...
閱讀 3288·2021-09-08 09:45
閱讀 1251·2019-08-30 15:53
閱讀 1522·2019-08-30 14:12
閱讀 981·2019-08-29 17:01
閱讀 2568·2019-08-29 15:35
閱讀 394·2019-08-29 13:09
閱讀 1965·2019-08-29 12:32
閱讀 3083·2019-08-26 18:37