Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

來源:互聯網
上載者:User

標籤:註冊   ant   length   sele   匹配   lin   一個   映射   control   

RequestMappingHandlerMapping:這個handlerMapping是基於註解的
同樣,先上類圖:

通過類圖可以看到,同樣是繼承父類 AbstractHandlerMapping來進行攔截器的初始化工作,實際上處理自己邏輯的只有下面三個類;
需要注意的是RequestMappingHandlerMapping初始化並不是重寫initApplicationContext()方法 ,而是通過實現InitializingBean介面來進行初始工作的。

備忘:InitializingBean介面為bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是實現該介面的類,在初始化bean的時候會執行該方法。
來看AbstractHandlerMethodMapping 中關鍵的代碼:
 1     public void afterPropertiesSet() { //實現了InitializingBean介面的方法,進行初始化的入口。 2         this.initHandlerMethods(); 3     } 4  5     protected void initHandlerMethods() { 6         if (this.logger.isDebugEnabled()) { 7             this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext()); 8         } 9      //掃描應用下所有Object類10         String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class) : this.getApplicationContext().getBeanNamesForType(Object.class);11         String[] arr$ = beanNames;12         int len$ = beanNames.length;13 14         for(int i$ = 0; i$ < len$; ++i$) {15             String beanName = arr$[i$];16             if (this.isHandler(this.getApplicationContext().getType(beanName))) { //ishandler由子類實現,是個鉤子方法,讓子類實現自己的邏輯17                 this.detectHandlerMethods(beanName);18             }19         }20 21         this.handlerMethodsInitialized(this.getHandlerMethods());//初始化處理器對象,目前是鉤子方法,但是也沒有子類實現這個方法22     }

isHandler方法是在RequestMappingHandlerMapping中實現的

1     protected boolean isHandler(Class<?> beanType) { //非常簡單, 就是看這個類有沒有Controller或者RequestMapping註解,有一個就行2         return AnnotationUtils.findAnnotation(beanType, Controller.class) != null || AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null;3     }

回到AbstractHandlerMethodMapping看:

 1     protected void detectHandlerMethods(Object handler) { //開始註冊handler 2         Class<?> handlerType = handler instanceof String ? this.getApplicationContext().getType((String)handler) : handler.getClass(); 3         final Class<?> userType = ClassUtils.getUserClass(handlerType);
      //這塊是擷取handelr的所有方法,但是有一個過濾器,就是把有匹配條件的的method擷取到 4 Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { 5 public boolean matches(Method method) { 6 return AbstractHandlerMethodMapping.this.getMappingForMethod(method, userType) != null;//getMappingForMethod鉤子方法,子類實現 7 } 8 }); 9 Iterator i$ = methods.iterator();10 //遍曆method 進行註冊。11 while(i$.hasNext()) {12 Method method = (Method)i$.next();13 T mapping = this.getMappingForMethod(method, userType);14 this.registerHandlerMethod(handler, method, mapping);15 }16 17 }

來看getMappingForMethod的實現,是在RequestMappingHandlerMapping實現的

 1     protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {  2         RequestMappingInfo info = null; //擷取方法上的RequestMapping註解資訊 3         RequestMapping methodAnnotation = (RequestMapping)AnnotationUtils.findAnnotation(method, RequestMapping.class); 4         if (methodAnnotation != null) { 5             RequestCondition<?> methodCondition = this.getCustomMethodCondition(method); 6             info = this.createRequestMappingInfo(methodAnnotation, methodCondition); 構造匹配條件
         // 擷取類上的面RequestHandlerMapping註解資訊 7 RequestMapping typeAnnotation = (RequestMapping)AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); 8 if (typeAnnotation != null) { 9 RequestCondition<?> typeCondition = this.getCustomTypeCondition(handlerType);10 info = this.createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); 構造匹配條件,同方法的進行合并11 }12 }13 14 return info;15 }

備忘下;RequestMappingInfo 實際上是匹配條件的一個抽象對象,包含了url,method,param,header...等等

來看註冊方法前,先看一下處理器是儲存在哪的;

1 public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {2     //這塊實際上是兩個map儲存的,泛型實際上就是RequestMappingInfo,這個就是匹配條件 HanlderMethod是封裝了處理器全部資訊的封裝類
3     private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap(); //存的是 key:匹配條件 value: 處理器4     private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap(); //key: url value: 匹配條件

這塊講一下MultiValueMap

public interface MultiValueMap<K, V> extends Map<K, List<V>> //實際上就是個 value是個list的map
 1     protected void registerHandlerMethod(Object handler, Method method, T mapping) { 2         HandlerMethod handlerMethod; 3         if (handler instanceof String) { 4             String beanName = (String)handler; 5             handlerMethod = new HandlerMethod(beanName, this.getApplicationContext(), method); 6         } else { 7             handlerMethod = new HandlerMethod(handler, method); 8         } 9 10         HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping);11         if (oldHandlerMethod != null && !oldHandlerMethod.equals(handlerMethod)) { //不允許存在一個mapping對應多個handlerMethod12             throw new IllegalStateException("Ambiguous mapping found. Cannot map ‘" + handlerMethod.getBean() + "‘ bean method \n" + handlerMethod + "\nto " + mapping + ": There is already ‘" + oldHandlerMethod.getBean() + "‘ bean method\n" + oldHandlerMethod + " mapped.");13         } else {14             this.handlerMethods.put(mapping, handlerMethod); //存放第一個映射集合15             if (this.logger.isInfoEnabled()) {16                 this.logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);17             }18 19             Set<String> patterns = this.getMappingPathPatterns(mapping); //擷取方法的URL20             Iterator i$ = patterns.iterator();21 22             while(i$.hasNext()) {23                 String pattern = (String)i$.next();24                 if (!this.getPathMatcher().isPattern(pattern)) { //依次放入第二個映射集合25                     this.urlMap.add(pattern, mapping);26                 }27             }28 29         }30     }

到此為止,RequestMappingHandlerMapping就初始化完成了。

疑問:  為什麼非註解映射器都是通過重寫initApplication方法,而註解映射器是通過實現iniliazingBean介面來初始化,這樣的好處是什嗎?

歡迎探討

Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.