SpringMVC中DispatcherServlet的HandlerMapping詳解
HandlerMapping
上回說的Handler,我們說是處理特定請求的。也就是說,不是所有的請求都能處理。那么問題來了,我們怎知道哪個請求是由哪個Handler處理的呢?
噔噔當,有請HandlerMapping閃亮登場。HandlerMapping就是處理uri到handler的映射的。從這個角度看他與Map有幾分相似,都是key-value。
然鵝,并不一樣!Spring的命名,你不得不服,就這點也給你整的明明白白。他是Handler+Mapping。
是映射Handler沒錯,但不是Map。我們的Handler可以處理特定的請求沒錯,但沒說只能處理一個特定請求啊。也可能是一個類似的patern的一系列路徑。
先看看定義:
public interface HandlerMapping {
/**
* 獲取Handler
*/
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
public interface MatchableHandlerMapping extends HandlerMapping {
/**
* 匹配請求路徑
*/
@Nullable
RequestMatchResult match(HttpServletRequest request, String pattern);
}我們可以發(fā)現(xiàn),他有兩個接口,其中MatchableHandlerMapping是HandlerMapping的派生接口。多了請求匹配接口方法。
這里介紹以下他的三個重要實現(xiàn):
| 實現(xiàn) | 介紹 |
| SimpleUrlHandlerMapping | 用于簡單映射URL到Handler。主要提供給客戶定制使用的,因此不會自動配置 |
| BeanNameUrlHandlerMapping | 如果Handler的beanName帶“/”的,就是由他來進行映射的。他會自動掃描容器中的beanName來識別handler,自動建立映射關系。在沒有配置HandlerMapping的情況下,會自動配置。 |
| RequestMappingHandlerMapping | 看名字就知道,他是為了@RequestMapping進行映射的。在沒有配置HandlerMapping的情況下,會自動配置 |

PS:社區(qū)版只能這樣看class diagrams了,勉強看吧。旗艦版的氪金大佬可以右鍵看氪金版的。 言歸正傳,SimpleUrlHandlerMapping特別簡單,只要告訴他哪個請求由哪個handler處理就行。可以調用他的setMapping(Properties mapping)方法,或者是setUrlMap。前者會被轉成Map給屬性urlMap賦值,而后者則是直接對urlMap賦值。
從繼承關系看,他繼承于AbstractUrlHandlerMapping。 AbstractUrlHandlerMapping實現(xiàn)了一系列基于url實現(xiàn)的HandlerMapping通用功能。
主要體現(xiàn)在,他通過ApplicationContextAware接口獲取到ApplicationContext,并且在該方法中獲取handler的beanName并轉換為實際handler對象。
并注冊到 org.springframework.web.reactive.handler.AbstractUrlHandlerMapping#handlerMap 。
得,到這里,應該知道,我們是在什么時候建立起URL跟Handler的關系了吧。
BeanNameUrlHandlerMapping
相較于SimpleUrlHandlerMapping,BeanNameUrlHandlerMapping則完全不需要用戶自己定義url到handler的關系。,而是自動檢測發(fā)現(xiàn)。前提是,你的handler在定義的時候beanName以“/”開頭。而關于他的秘密也同樣在他的繼承關系圖里:

與SimpleUrlHandlerMapping類似,他也是基于ApplicationContextAware接口進行擴展而來的能力。
在獲得上下文后,通過上下文遍歷所有的beanName,就能知道這個bean是不是一個handler了。
封裝HandlerExecutionChain
此時,必須提醒一下大家,HandlerMapping接口的返回值是HandlerExecutionChain,并不是Handler。前面不管是說哪個HandlerMapping,都只是在說怎么尋找Handler、以及怎么注冊??蓻]有說HandlerExecutionChain。其實,這得益于他們公共的父類方法 org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler 。這也意味著,封裝HandlerExecutionChain是在每個請求進來的時候才封裝的。具體代碼:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}代碼也比較簡單。這里面還讓我們多認識了MappedInterceptor,他可以針對特定的請求進行攔截。
總結
上面講的兩款都是基于AbstractUrlHandlerMapping擴展出來的HandlerMapping。而AbstractUrlHandlerMapping處理的都是基于URL來處理的,意味著不會有其他的可以匹配的條件。
Handler注冊中心則有兩種。
| Handler注冊方式 | Handler注冊中心 |
| 基于URL 注冊 | Map<String, Object> handlerMap = new LinkedHashMap<>(); |
| 基于pattern注冊的 | Map<PathPattern, Object> pathPatternHandlerMap = new LinkedHashMap<>(); |
但都是簡單Map就能搞定。
- HandlerMapping的作用是尋找匹配的Handler,與Handler的類型無關,不存在一一對應關系。
- 封裝HandlerExecutionChain是在獲取Handler時,在公共父類AbstractHandlerMapping里實現(xiàn)的。
到此這篇關于SpringMVC中DispatcherServlet的HandlerMapping詳解的文章就介紹到這了,更多相關HandlerMapping詳解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
老生常談foreach(增強for循環(huán))和for的區(qū)別
下面小編就為大家?guī)硪黄仙U刦oreach(增強for循環(huán))和for的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
SpringBoot之通過BeanPostProcessor動態(tài)注入ID生成器案例詳解
這篇文章主要介紹了SpringBoot之通過BeanPostProcessor動態(tài)注入ID生成器案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-09-09
Spring Cloud Stream微服務消息框架原理及實例解析
這篇文章主要介紹了Spring Cloud Stream微服務消息框架原理及實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06

