SpringMVC中DispatcherServlet的HandlerMapping詳解
HandlerMapping
上回說(shuō)的Handler,我們說(shuō)是處理特定請(qǐng)求的。也就是說(shuō),不是所有的請(qǐng)求都能處理。那么問(wèn)題來(lái)了,我們?cè)踔滥膫€(gè)請(qǐng)求是由哪個(gè)Handler處理的呢?
噔噔當(dāng),有請(qǐng)HandlerMapping閃亮登場(chǎng)。HandlerMapping就是處理uri到handler的映射的。從這個(gè)角度看他與Map有幾分相似,都是key-value。
然鵝,并不一樣!Spring的命名,你不得不服,就這點(diǎn)也給你整的明明白白。他是Handler+Mapping。
是映射Handler沒(méi)錯(cuò),但不是Map。我們的Handler可以處理特定的請(qǐng)求沒(méi)錯(cuò),但沒(méi)說(shuō)只能處理一個(gè)特定請(qǐng)求啊。也可能是一個(gè)類(lèi)似的patern的一系列路徑。
先看看定義:
public interface HandlerMapping { /** * 獲取Handler */ @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } public interface MatchableHandlerMapping extends HandlerMapping { /** * 匹配請(qǐng)求路徑 */ @Nullable RequestMatchResult match(HttpServletRequest request, String pattern); }
我們可以發(fā)現(xiàn),他有兩個(gè)接口,其中MatchableHandlerMapping是HandlerMapping的派生接口。多了請(qǐng)求匹配接口方法。
這里介紹以下他的三個(gè)重要實(shí)現(xiàn):
實(shí)現(xiàn) | 介紹 |
SimpleUrlHandlerMapping | 用于簡(jiǎn)單映射URL到Handler。主要提供給客戶(hù)定制使用的,因此不會(huì)自動(dòng)配置 |
BeanNameUrlHandlerMapping | 如果Handler的beanName帶“/”的,就是由他來(lái)進(jìn)行映射的。他會(huì)自動(dòng)掃描容器中的beanName來(lái)識(shí)別handler,自動(dòng)建立映射關(guān)系。在沒(méi)有配置HandlerMapping的情況下,會(huì)自動(dòng)配置。 |
RequestMappingHandlerMapping | 看名字就知道,他是為了@RequestMapping進(jìn)行映射的。在沒(méi)有配置HandlerMapping的情況下,會(huì)自動(dòng)配置 |
PS:社區(qū)版只能這樣看class diagrams了,勉強(qiáng)看吧。旗艦版的氪金大佬可以右鍵看氪金版的。 言歸正傳,SimpleUrlHandlerMapping特別簡(jiǎn)單,只要告訴他哪個(gè)請(qǐng)求由哪個(gè)handler處理就行??梢哉{(diào)用他的setMapping(Properties mapping)方法,或者是setUrlMap。前者會(huì)被轉(zhuǎn)成Map給屬性u(píng)rlMap賦值,而后者則是直接對(duì)urlMap賦值。
從繼承關(guān)系看,他繼承于AbstractUrlHandlerMapping。 AbstractUrlHandlerMapping實(shí)現(xiàn)了一系列基于url實(shí)現(xiàn)的HandlerMapping通用功能。
主要體現(xiàn)在,他通過(guò)ApplicationContextAware接口獲取到ApplicationContext,并且在該方法中獲取handler的beanName并轉(zhuǎn)換為實(shí)際handler對(duì)象。
并注冊(cè)到 org.springframework.web.reactive.handler.AbstractUrlHandlerMapping#handlerMap
。
得,到這里,應(yīng)該知道,我們是在什么時(shí)候建立起URL跟Handler的關(guān)系了吧。
BeanNameUrlHandlerMapping
相較于SimpleUrlHandlerMapping,BeanNameUrlHandlerMapping則完全不需要用戶(hù)自己定義url到handler的關(guān)系。,而是自動(dòng)檢測(cè)發(fā)現(xiàn)。前提是,你的handler在定義的時(shí)候beanName以“/”開(kāi)頭。而關(guān)于他的秘密也同樣在他的繼承關(guān)系圖里:
與SimpleUrlHandlerMapping類(lèi)似,他也是基于ApplicationContextAware接口進(jìn)行擴(kuò)展而來(lái)的能力。
在獲得上下文后,通過(guò)上下文遍歷所有的beanName,就能知道這個(gè)bean是不是一個(gè)handler了。
封裝HandlerExecutionChain
此時(shí),必須提醒一下大家,HandlerMapping接口的返回值是HandlerExecutionChain,并不是Handler。前面不管是說(shuō)哪個(gè)HandlerMapping,都只是在說(shuō)怎么尋找Handler、以及怎么注冊(cè)。可沒(méi)有說(shuō)HandlerExecutionChain。其實(shí),這得益于他們公共的父類(lèi)方法 org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
。這也意味著,封裝HandlerExecutionChain是在每個(gè)請(qǐng)求進(jìn)來(lái)的時(shí)候才封裝的。具體代碼:
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; }
代碼也比較簡(jiǎn)單。這里面還讓我們多認(rèn)識(shí)了MappedInterceptor,他可以針對(duì)特定的請(qǐng)求進(jìn)行攔截。
總結(jié)
上面講的兩款都是基于AbstractUrlHandlerMapping擴(kuò)展出來(lái)的HandlerMapping。而AbstractUrlHandlerMapping處理的都是基于URL來(lái)處理的,意味著不會(huì)有其他的可以匹配的條件。
Handler注冊(cè)中心則有兩種。
Handler注冊(cè)方式 | Handler注冊(cè)中心 |
基于URL 注冊(cè) | Map<String, Object> handlerMap = new LinkedHashMap<>(); |
基于pattern注冊(cè)的 | Map<PathPattern, Object> pathPatternHandlerMap = new LinkedHashMap<>(); |
但都是簡(jiǎn)單Map就能搞定。
- HandlerMapping的作用是尋找匹配的Handler,與Handler的類(lèi)型無(wú)關(guān),不存在一一對(duì)應(yīng)關(guān)系。
- 封裝HandlerExecutionChain是在獲取Handler時(shí),在公共父類(lèi)AbstractHandlerMapping里實(shí)現(xiàn)的。
到此這篇關(guān)于SpringMVC中DispatcherServlet的HandlerMapping詳解的文章就介紹到這了,更多相關(guān)HandlerMapping詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot集成kafka全面實(shí)戰(zhàn)記錄
在實(shí)際開(kāi)發(fā)中,我們可能有這樣的需求,應(yīng)用A從TopicA獲取到消息,經(jīng)過(guò)處理后轉(zhuǎn)發(fā)到TopicB,再由應(yīng)用B監(jiān)聽(tīng)處理消息,即一個(gè)應(yīng)用處理完成后將該消息轉(zhuǎn)發(fā)至其他應(yīng)用,完成消息的轉(zhuǎn)發(fā),這篇文章主要介紹了SpringBoot集成kafka全面實(shí)戰(zhàn),需要的朋友可以參考下2021-11-11老生常談foreach(增強(qiáng)for循環(huán))和for的區(qū)別
下面小編就為大家?guī)?lái)一篇老生常談foreach(增強(qiáng)for循環(huán))和for的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Java web過(guò)濾器驗(yàn)證登錄防止未登錄進(jìn)入界面
這篇文章主要介紹了Java web過(guò)濾器驗(yàn)證登錄防止未登錄進(jìn)入界面,在一些系統(tǒng)中經(jīng)??梢杂玫酱斯δ埽瑢?duì)java web 驗(yàn)證登錄知識(shí)感興趣的朋友一起看下吧2016-08-08SpringBoot之通過(guò)BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解
這篇文章主要介紹了SpringBoot之通過(guò)BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09Spring Cloud Stream微服務(wù)消息框架原理及實(shí)例解析
這篇文章主要介紹了Spring Cloud Stream微服務(wù)消息框架原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06