本節咱們繼續分析HandlerMapping另外一個實現類ReqeustMappingHandlerMapping,該類是咱們平常開發中使用最多的映射器策略,即咱們在開發中使用的註解開發方式,如:@Controller、@RequestMapping等,都使用的是此映射策略。Spring MVC默認支持該策略。app
本系列文章是基於Spring5.0.5RELEASE。cors
類的繼承關係,以下圖:ide
第一次看到此圖可能會感受好複雜,你們別急,學技術就是這樣,首先須要靜下心,再一個要學會對已掌握知識點作總結、對比、分類,這樣才能把全部的知識點串起來,能系統的瞭解一項技術。源碼分析
以上是我我的的一些經驗,但願對別人能有幫助,廢話很少說了,咱們來分析下這張圖,以前咱們學過了SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping,經過橫向對比,咱們發現,他們都繼承自AbstractHandlerMapping抽象類,而AbstractHandlerMapping類的主要工做就是初始化攔截器的功能,三者的實現都是同樣的。學習
繼續分析,咱們發現RequestMappingHandlerMapping增長實現了InitializingBean和EmbeddedVualeResolverAware接口,即增長了以下能力:ui
這兩個接口都是Spring自動幫咱們調用其中的方法的。也就是說,RequestMappingHandlerMapping經過這些能力來完成初始化HandlerMapping接口的。this
以上是對RequestMappingHandlerMapping的宏觀分析,下面咱們進行內部細節分析。url
1、經過實現ApplicationContextAware接口,完成攔截器相關組件的初始化spa
2、經過實現InitializingBean接口,完成url與處理器方法的映射(url->RequestMappingInfo,RequstMappingInfo->HandlerMehtod)debug
調用RequestMappingHandlerMapping類實現的afterPropertiesSet()方法,經過該方法最終調到其父類的initHandlerMethods()方法,這個方法是完成映射解析工做:
一、獲取上下文環境中全部的bean
二、迭代全部的bean,經過isHandler方法判斷是不是handler
2.1 調用RequestMappingHandlerMapping.isHandler方法,根據@Controller或@RequestMapping註解判斷(「或」關係,任意一個)三、解析出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
四、對HandlerMethod進行初始化,調用handlerMethodsInitialized方法,其內部什麼都沒作
以上是初始化RequestMappingHandlerMapping的總體流程。
初始化攔截器
// 初始化攔截器,即初始化url須要的攔截器 @Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.adaptedInterceptors); initInterceptors(); }
控制初始化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註解的方法 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) 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<String> 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<String> getDirectUrls(T mapping) { List<String> urls = new ArrayList<>(1); // 調用子類RequestMappingInfoHandlerMapping.getMappingPathPatterns方法 for (String path : getMappingPathPatterns(mapping)) { if (!getPathMatcher().isPattern(path)) { urls.add(path); } } return urls; }
根據@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(); }
提供匹配條件RequestMappingInfo的解析處理,涉及的代碼以下:
/** * 獲取url集合,即@RequestMapping中設置的value或path */ @Override protected Set<String> getMappingPathPatterns(RequestMappingInfo info) { return info.getPatternsCondition().getPatterns(); }
以上即RequestMappingHandlerMapping對象的初始化過程及初始化過程的核心源碼。
本文主要分析了RequestMappingHandlerMapping的初始化過程,但願對你們有幫助。隨着學習的深刻,後面有時間在分析下期中涉及的關鍵bean,好比:RequestMappingInfo、RequestCondition、HandlerMethod等等。你們加油!
最後建立了qq羣方便你們交流,可掃描加入,同時也可加我qq:276420284,共同窗習、共同進步,謝謝!