HandlerMapping將url分發到對應的handler處理器,並添加攔截器. 實現上,經典的介面+抽象類+具體演算法實現.
SpringMVC在請求到handler處理器的分發這步是通過HandlerMapping模塊解決的.handlerMapping 還處理攔截器.
先看看HandlerMapping的繼承樹吧
可以大致這樣做個分類:
1. 一個介面HandlerMapping,定義一個api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
2. 一個基礎抽象類:主要是準備上下文環境,提供getHandlerInternal鉤子,封裝攔截器到HandlerExecutionChain
3. 基於註解@Controller,@RequestMapping的使用
4. 配置文件中直接配置url到 handler的SimpleUrlHandlerMapping
5. 預設實現BeanNameUrlHandlerMapping
6. Controller子類的映射
看看HandlerMapping吧,就一個getHandler api 非常簡單.
// HandlerMapping
1 package org.springframework.web.servlet; 2 public interface HandlerMapping { 3 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; 4 5 }
AbstractHandlerMapping就沒有這麼簡單了
先看AbstractHandlerMapping繼承的類,實現的介面
1 package org.springframework.web.servlet.handler; 2 public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport 3 implements HandlerMapping, Ordered { 4 // ... 5 }
WebApplicationObjectSupport用於提供上下文ApplicationContext和ServletContext.
還有這邊的initApplicationContext方法,在後續經常會使用到.AbstractHandlerMapping就直接覆寫了.
父類里還是實現了ApplicationContextAware和ServletContextAware介面,spring概念很統一.
Ordered用於集合排序.
再接著看AbstractHandlerMapping的屬性吧
// AbstractHandlerMapping
1 // order賦了最大值,優先順序是最小的 2 private int order = Integer.MAX_VALUE; // default: same as non-Ordered 3 // 預設的Handler,這邊使用的Obejct,子類實現的時候,使用HandlerMethod,HandlerExecutionChain等 4 private Object defaultHandler; 5 // url計算的輔助類 6 private UrlPathHelper urlPathHelper = new UrlPathHelper(); 7 // 基於ant進行path匹配,解決如/books/{id}場景 8 private PathMatcher pathMatcher = new AntPathMatcher(); 9 // 攔截器配置:1,HandlerMapping屬性設置;2,extendInterceptors設置 10 private final List<Object> interceptors = new ArrayList<Object>(); 11 // 從interceptors中解析得到,直接添加給全部handler 12 private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>(); 13 // 使用前需要跟url進行匹配,匹配通過才會使用 14 private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
看下攔截器的初始化:
// AbstractHandlerMapping
1 @Override 2 protected void initApplicationContext() throws BeansException { 3 extendInterceptors(this.interceptors); 4 detectMappedInterceptors(this.mappedInterceptors); 5 initInterceptors(); 6 } 7 8 /** 9 * 提供給子類擴展攔截器,可惜都沒有使用 10 */ 11 protected void extendInterceptors(List<Object> interceptors) { 12 } 13 14 /** 15 * 掃描應用下的MappedInterceptor,並添加到mappedInterceptors 16 */ 17 protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) { 18 mappedInterceptors.addAll( 19 BeanFactoryUtils.beansOfTypeIncludingAncestors( 20 getApplicationContext(),MappedInterceptor.class, true, false).values()); 21 } 22 23 /** 24 * 歸集MappedInterceptor,並適配HandlerInterceptor和WebRequestInterceptor 25 */ 26 protected void initInterceptors() { 27 if (!this.interceptors.isEmpty()) { 28 for (int i = 0; i < this.interceptors.size(); i++) { 29 Object interceptor = this.interceptors.get(i); 30 if (interceptor == null) { 31 throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); 32 } 33 if (interceptor instanceof MappedInterceptor) { 34 mappedInterceptors.add((MappedInterceptor) interceptor); 35 } 36 else { 37 adaptedInterceptors.add(adaptInterceptor(interceptor)); 38 } 39 } 40 } 41 } 42 43 protected HandlerInterceptor adaptInterceptor(Object interceptor) { 44 if (interceptor instanceof HandlerInterceptor) { 45 return (HandlerInterceptor) interceptor; 46 } 47 else if (interceptor instanceof WebRequestInterceptor) { 48 return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor); 49 } 50 else { 51 throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName()); 52 } 53 }
然後是getHandler(HttpServletRequest request)的實現,這邊同時預留getHandlerInternal(HttpServletRequest request)給子類實現
// AbstractHandlerMapping
1 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 2 Object handler = getHandlerInternal(request); 3 if (handler == null) { 4 handler = getDefaultHandler(); 5 } 6 if (handler == null) { 7 return null; 8 } 9 // Bean name or resolved handler? 10 if (handler instanceof String) { 11 String handlerName = (String) handler; 12 handler = getApplicationContext().getBean(handlerName); 13 } 14 return getHandlerExecutionChain(handler, request); 15 } 16 17 protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
最後是封裝攔截器到HandlerExecutionChain
adaptedInterceptors直接添加
mappedInterceptors需要根據url匹配通過後添加
// AbstractHandlerMapping
1 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { 2 HandlerExecutionChain chain = 3 (handler instanceof HandlerExecutionChain) ? 4 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler); 5 6 chain.addInterceptors(getAdaptedInterceptors()); 7 8 String lookupPath = urlPathHelper.getLookupPathForRequest(request); 9 for (MappedInterceptor mappedInterceptor : mappedInterceptors) { 10 if (mappedInterceptor.matches(lookupPath, pathMatcher)) { 11 chain.addInterceptor(mappedInterceptor.getInterceptor()); 12 } 13 } 14 15 return chain; 16 }
Controller子類的映射,這一分支先看類繼承
我們來說說,這邊每個類主要的職責
1. AbstractHandlerMapping 準備上下文環境;提供getHandlerInternal鉤子;封裝攔截器到HandlerExecutionChain
2. AbstractUrlHandlerMapping 實現註冊handler的方法供子類使用;實現getHandlerInternal,根據子類初始化的配置信息,查找handler
3. AbstractDetectingUrlHandlerMapping 掃描應用下的Object,迭代後提供鉤子方法determineUrlsForHandler由子類決定如何過濾
4. AbstractControllerUrlHandlerMapping 實現determineUrlsForHandler,添加過濾排除的handler操作(配置文件配置),預留鉤子方法buildUrlsForHandler給子類實現;同時判斷controller的子類
5. ControllerBeanNameHandlerMapping 根據bean name生成url
ControllerClassNameHandlerMapping根據class name生成url
從AbstractUrlHandlerMapping開始看吧,這邊只是大致看下代碼,如果需要仔細分析,請移步<SpringMVC源碼解讀 - HandlerMapping - AbstractUrlHandlerMapping系列request分發>
handler的註冊
1 protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { } 2 3 protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { }
handler的查找
1 protected Object getHandlerInternal(HttpServletRequest request) throws Exception {} 2 // 根據url查找handler 3 protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {} 4 // 校驗handler 5 protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {} 6 // 封裝攔截器到HandlerExecutionChain 7 protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, 8 String pathWithinMapping, Map<String, String> uriTemplateVariables) {}
AbstractDetectingUrlHandlerMapping,這邊一樣不展開,具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>
具體做的事情:
1. 通過覆寫initApplicationContext,調用detectHandlers掃描Obejct
2. 提供鉤子方法determineUrlsForHandler給子類根據handler生成url
3. 調用父類的registerHandler進行註冊
1 @Override 2 public void initApplicationContext() throws ApplicationContextException { 3 super.initApplicationContext(); 4 detectHandlers(); 5 } 6 7 protected void detectHandlers() throws BeansException { 8 // ... 9 } 10 11 12 /** 13 * Determine the URLs for the given handler bean. 14 * 鉤子而已 15 */ 16 protected abstract String[] determineUrlsForHandler(String beanName);
AbstractControllerUrlHandlerMapping,這邊一樣不展開,具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>
具體做的事情;
1. 覆寫determineUrlsForHandler添加剔除部分類的邏輯,通過配置文件配置的excludedClasses和excludedPackages在這邊使用
2. 判斷是否controller的子類
3. 預留buildUrlsForHandler給子類生成url
1 @Override 2 protected String[] determineUrlsForHandler(String beanName) { 3 Class beanClass = getApplicationContext().getType(beanName); 4 if (isEligibleForMapping(beanName, beanClass)) { 5 return buildUrlsForHandler(beanName, beanClass); 6 } 7 else { 8 return null; 9 } 10 } 11 12 protected boolean isEligibleForMapping(String beanName, Class beanClass) {} 13 14 protected boolean isControllerType(Class beanClass) {} 15 16 protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);
ControllerBeanNameHandlerMapping和ControllerClassNameHandlerMapping 直接看源碼吧,或者移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>
配置文件中直接配置url到 handler的SimpleUrlHandlerMapping,就是使用registerHandlers註冊配置文檔中的handler,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - SimpleUrlHandlerMapping初始化>吧
BeanNameUrlHandlerMapping 實現determineUrlsForHandler生成url,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>吧
基於註解@Controller,@RequestMapping的使用
最難吭的骨頭
先看類繼承吧
說下各個類的職責吧,具體的分析還是移步下麵的文章
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping初始化>
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping請求分發>
1. AbstractHandlerMethodMaping 定義初始化流程,請求時如何映射
初始化:
1.1.1 掃描應用下的Object
1.1.2 預留isHandler鉤子方法給子類判斷Object是否handler
1.1.3 迭代掃描每一個handler,找出符合要求的方法,這邊判斷依然是留給子類實現getMappingForMethod
1.1.4 註冊查找到的處理器,需要確保一個匹配條件RequestMappingInfo只能映射到一個handler
1.1.5 根據匹配條件獲取url,同樣的只是定義流程,具體的演算法留給子類實現getMappingPathPatterns
請求request分發處理:
1.2.1 直接字元串匹配的方式,查找handler
1.2.2 匹配條件查找,這邊具體的演算法交由子類處理getMatchingMapping
1.2.3 排序並獲取最佳匹配handler,這邊的排序方式還是子類處理getMappingConmparator
1.2.4 分別封裝匹配到和未匹配到handler的情況
2. RequestMappingInfoHandlerMapping使用RequestMappingInfo實現匹配條件,RequestMappingInfo的初始化留給子類
2.1 根據RequestMappingInfo生成url ->getMappingPathPatterns
2.2 使用匹配條件查找Handler -> getMatchingMapping
2.3 完成比較器演算法 -> getMappingComparator
2.4 覆寫handleMatch,緩存n多信息到request
註冊pattern,最佳匹配的pattern,url中解析出來的參數,url中解析出來的多值參數,mediaType
2.1.5 覆寫handlerNoMatch,最後的掙扎,再嘗試匹配一次
3. RequestMappingHandlerMapping 根據註解@Controller @RequestMapping生成RequestMappingInfo,並校驗isHandler
3.1 覆寫afterPropertiesSet,添加文件尾碼判斷
3.2 實現isHandler,類上有@Controller @RequestMapping其中一個註解就對
3.3 解析註解內容,生產RequestMappingInfo實例