Spingmvc中的HandlerMapping剖析
HandlerMapping
1、請(qǐng)求首先進(jìn)入DispatcherServlet, 由DispatcherServlet 從HandlerMappings中匹配對(duì)應(yīng)的Handler,此時(shí)只是獲取到了對(duì)應(yīng)的Handler,然后拿著這個(gè)Handler去尋找對(duì)應(yīng)的適配器,即:HandlerAdapter;
2、拿到對(duì)應(yīng)HandlerAdapter時(shí),這時(shí)候開(kāi)始調(diào)用對(duì)應(yīng)的Handler方法,即執(zhí)行我們的Controller來(lái)處理業(yè)務(wù)邏輯了, 執(zhí)行完成之后返回一個(gè)ModeAndView;
3、HandlerAdapter執(zhí)行完之后,返回一個(gè)ModeAndView,把它交給我們的視圖解析器ViewResolver,通過(guò)視圖名稱查找出對(duì)應(yīng)的視圖然后返回;
4、最后,渲染視圖 返回渲染后的視圖。
在介紹HandlerMapping、HandlerAdapter之前,先來(lái)說(shuō)一下SpringMVC中定義Handler的方式,本人就是對(duì)這個(gè)知識(shí)點(diǎn)不熟悉,導(dǎo)致對(duì)這兩個(gè)對(duì)象一直不明白。
先說(shuō)一下最最最最……常用定義Handler的方式,使用@RequestMapping注解,下面這段代碼不用介紹吧:
@Controller public class IndexController { @RequestMapping("/index") @ResponseBody public String sayHello(){ System.out.println("hello ..."); return "hello"; } }
那大家有沒(méi)有用過(guò)下面的兩種方式來(lái)聲明一個(gè)Handler呢??
實(shí)現(xiàn)org.springframework.web.servlet.mvc.Controller控制器接口,此接口只有一個(gè)方法handleRequest(),用于請(qǐng)求的處理,返回ModelAndView。 這個(gè)接口從第一版SpringMVC就存在了,所以這個(gè)接口是非常古老的接口~~~也是Spring MVC最早期的實(shí)現(xiàn)Handler的方式
// 關(guān)注一下這個(gè)包 import org.springframework.web.servlet.mvc.Controller; @Component("/home") public class HomeController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("home ..."); return null; } // 這地方考慮個(gè)問(wèn)題:怎么樣實(shí)現(xiàn)類似@ResponseBody的功能呢? // 就是想實(shí)現(xiàn)直接向body里寫數(shù)據(jù),而不是返回一個(gè)頁(yè)面。 // 如果想直接在處理器/控制器里使用response向客戶端寫回?cái)?shù)據(jù), // 可以通過(guò)返回null來(lái)告訴 DispatcherServlet我們已經(jīng)寫出響應(yīng)了, // 不需要它進(jìn)行視圖解析。像下面這樣 @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("home ..."); response.getWriter().write("home controller from body"); return null; // 返回null告訴視圖渲染 直接把body里面的內(nèi)容輸出瀏覽器即可 } }
Spingmvc中的HandlerMapping負(fù)責(zé)解析請(qǐng)求URL,對(duì)應(yīng)到Handler進(jìn)行處理(這里的Handler一般為Controller里的一個(gè)方法method,也可以為servlet或者Controller等)
來(lái)看一個(gè)http請(qǐng)求的入口DispatcherServlet:
- DispatcherServlet繼承FrameworkServlet,F(xiàn)rameworkServlet繼承HttpServletBean,HttpServletBean繼承HttpServlet。
可以看出,springmvc的DispatcherServlet是在Servelt的基礎(chǔ)上做了擴(kuò)展處理。
doService方法為servlet處理請(qǐng)求的入口,DispatcherServlet中做了方法覆蓋,doService方法中的doDispatch(request,response)方法,是springmvc處理整個(gè)請(qǐng)求流程的關(guān)鍵。
- mappedHandler =getHandler(processedRequest);
- 這行代碼實(shí)現(xiàn)了為請(qǐng)求尋找處理handler,返回的是HandlerExecutionChain;
- HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());
- 找到處理handler后,再去找匹配的HandlerAdapter,HandlerAdapter將完成后續(xù)處理。
繼續(xù)看是如何找到請(qǐng)求對(duì)應(yīng)的處理handler的:
- 可以看出是從類變量this.handlerMappings中循環(huán)獲取,當(dāng)找到與之匹配的HandlerMapping時(shí),返回類型為HandlerExecutionChain的handler。
這里this.handlerMappings中的值是從哪獲取的呢?DispatcherServlet初始化的時(shí)候會(huì)給this.handlerMappings賦值:
- 從這里可以看出,在servlet初始化的時(shí)候,會(huì)對(duì)springmvc的HandlerMappings、HandlerAdapters等做初始化。
- 這里三個(gè)步驟,先對(duì)springmvc.xml里配置的HandlerMapping進(jìn)行初始化、實(shí)例化,再對(duì)this.handlerMappings賦值,最后對(duì)this.handlerMappings進(jìn)行排序。
- 這里的排序就是對(duì)HandlerMapping的order屬性進(jìn)行排序,這樣,order屬性值小的,就可以先對(duì)請(qǐng)求進(jìn)行匹配。
- 從tomcat啟動(dòng)日志里可以看到HandlerMapping的初始化:
這里涉及到兩個(gè)HandlerMapping:
- 第一個(gè)是BeanNameUrlHandlerMapping,初始化時(shí)會(huì)將urlpath做映射存儲(chǔ);
- 第二個(gè)是RequestMappingHandlerMapping,初始化時(shí)會(huì)將Controller中配置@RequestMapping注解的方法做映射存儲(chǔ)。
HandlerMapping初始化時(shí),會(huì)將映射與handler存儲(chǔ)到map里;處理請(qǐng)求時(shí),從map里取出對(duì)應(yīng)的處理handler。
這就是HandlerMapping在springmvc里的大致處理流程。
到此這篇關(guān)于SpringBoot中的HandlerMapping剖析的文章就介紹到這了,更多相關(guān)SpringBoot的HandlerMapping內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java int與integer的對(duì)比區(qū)別
這篇文章主要介紹了Java int與integer的對(duì)比區(qū)別的相關(guān)資料,需要的朋友可以參考下2017-01-01Java編程在ICPC快速IO實(shí)現(xiàn)源碼
這篇文章主要介紹了Java Fast IO in ICPC實(shí)現(xiàn)源碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-09-09springboot植入pagerHelper的超詳細(xì)教程
這篇文章主要介紹了springboot植入pagerHelper的超詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01SpringBoot3整合SpringCloud啟動(dòng)后nacos報(bào)錯(cuò)獲取不到配置、無(wú)法注冊(cè)服務(wù)的解決方案
文章介紹了如何使用Spring Boot 3.3.4和Spring Cloud 2023.0.3搭建微服務(wù)項(xiàng)目,并解決與Nacos服務(wù)注冊(cè)發(fā)現(xiàn)和配置中心的集成問(wèn)題,主要解決了依賴版本不兼容、配置文件導(dǎo)入問(wèn)題及服務(wù)注冊(cè)失敗等問(wèn)題,感興趣的朋友跟隨小編一起看看吧2025-02-02Spring?Boot異步線程間數(shù)據(jù)傳遞的四種方式
這篇文章主要為大家介紹了Spring?Boot異步線程間數(shù)據(jù)傳遞的四種方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01關(guān)于Java HashMap自動(dòng)排序的簡(jiǎn)單剖析
這篇文章主要給大家介紹了關(guān)于Java HashMap自動(dòng)排序的簡(jiǎn)單剖析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09