1. 程式人生 > >Spring mvc之源碼 handlerMapping和handlerAdapter分析

Spring mvc之源碼 handlerMapping和handlerAdapter分析

執行方法 work 默認 生命 以及 nco refresh 實現 初始化

 Spring mvc之源碼 handlerMapping和handlerAdapter分析

本篇並不是具體分析Spring mvc,所以好多細節都是一筆帶過,主要是帶大家梳理一下整個Spring mvc的執行流程,以及如何根據URL查找處理器Controller的實現

(適合那些剛閱讀源碼不知道如何下手的人)

http://www.guojinbao.com/borrow/borrowDetail/GETadLPjnf0[d].do

如何根據URL地址----》找到正確處理器Controller的相應方法Method

註:概念 IOC容器:負責bean的創建和維護beanbean關系的一個大的集合

dispatcherServlet

Spring MVC為所有請求入口,標準的servlet

標準的servlet執行流程為

1.init() 首次加載servlet 整個servlet生命周期只執行一次

2.service() 依據url-pattern<url-pattern>/</url-pattern> 攔截所有請求,不包括靜態資源文件) 攔截模式,匹配請求模式,匹配成功調用service方法

3.destroy() servlet容器(如:tomcat停止)結束調用

技術分享

執行流程如下

第一步 執行 HttpServletBean-->init()方法

技術分享

init()方法我們只需要關註

initServletBean()方法 此方法為抽象方法由FrameworkServlet實現

技術分享

有興趣的可以具體看一下源碼,整個init()方法 為spring mvcIOC容器初始化

Spring IOC容器初始化由contextLoaderListener完成

技術分享

Spring IOC容器建議配置:數據庫連接,事務,與第三方框架集成等等

如:ApplicationContext.xml (小提示:處理器Controller的掃描 可以交給springMVC IOC容器完成,目的分層明確,便於IOC容器查找 )  

技術分享

Spring mvc IOC 容器 配置:

技術分享

第二部

攔截請求

FrameworkServlet -->service()

分發請求

FrameworkServlet--->processRequest(request, response);

DispatcherServlet--->doService(HttpServletRequest request, HttpServletResponse response)

如何根據URL找到處理器執行正確的方法就在此方法中

DispatcherServlet--->doDispatch(HttpServletRequest request, HttpServletResponse response)

①部分

技術分享

這裏為啥不是調用super.service(request,response)?

技術分享

最直接的理由:如果直接調用service方法 根據method類型進行分發請求就直接跳出框架啦(你懂的嘿嘿)

②③2步有興趣的可以看一下源碼

④部分

DispatcherServlet--->doDispatch(HttpServletRequest request, HttpServletResponse response)

技術分享

技術分享

整個過程如下:

>>1. 獲取url對應的處理器controller以及相應方法

>>2. 獲取執行處理器中方法的對象

>>3. 具體執行

Spring mvc是如何通過URL查找到對應的處理器controller以及對應的方法尼?需要知道以下3個核心接口handlerMapping,handlerAdapter,RequestCondition我們不具體分析相應接口的實現以及具體邏輯,過程相當復雜,12句話說

不清楚,這裏給大家留一個直觀的考量。

由於Spring mvc源碼龐大,建議看源碼的時候,只看重點部分或者說自己感興趣部分。我們大家常用是在類和方法加上註解@RequestMapping來標識訪問路徑,我們以此模板給大家量化分析url查詢處理器controller以及相應方法的過程

handlerMapping:負責查找URL對應的處理器Controller

RequestMappingInfo:[email protected]

handlerAdapter:負責綁定參數,執行請求,處理返回值

handlerMapping 接口就一個方法返回HandlerExecutionChain

技術分享

HandlerExecutionChain

技術分享

DispatcherServlet--->doDispatch()

第一步 獲取HandlerExecutionChain

技術分享

技術分享

DispatcherServlteservlet初始化中(調用init()方法)中調用onRefresh()完成handlerMappings的初始化

技術分享

第二步 獲取handlerAdapter 找到和handlerMapping匹配的handlerAdapter

技術分享

初始化過程同第一步

DispatcherServlte會根據handlerMapping與已經註冊好了的HandlerAdapter一一匹配,看哪一種HandlerAdapter是支持該handlerMapping類型的,

如果找到了其中一種HandlerAdapter是支持傳過來的handlerMapping類型,那麽該HandlerAdapter會調用自己的handle方法,handle方法運用Java的反射機制執行controller的具體方法來獲得ModelAndView

handlerMapping的實現RequestMappingHandlerMapping為例

技術分享

由於實現了InitializingBean,當RequestMappingHandlerMapping完成bean的初始化後,會調用afterPropertiesSet()-->initHandlerMethods();完成以下操作

①生成直接URL-->RequestMappingInfo,映射操作

技術分享

②生成 RequestMappingInfo--->handlerMethod映射操作

技術分享

將所有的RequestMappingInfo註冊到容器中

註:

RequestMappingInfo實現了RequestCondition接口 存儲著[email protected]

舉個例子

技術分享

技術分享

PatternsRequestCondition的初始化相當於

PatternsRequestCondition“/user/applicationShow/{id}”)當請求URL符合此規則是就匹配成功

簡單滴說,RequestMappingInfo是將註解@RequestMapping的信息提取出來

成此方法的匹配條件

技術分享

閱讀RequestMappingHandlerMapping源碼流程如下(主要是為了梳理出重點部分)

技術分享

技術分享

技術分享

技術分享

綜上所述我們來猜測一下spring mvc 中根據URL找到處理器Controller中相應方法的流程

①:獲取RequestURL

②:從UrlLookup這個map中找到相應的requestMappingInfo

③:如果沒找到則遍歷所有requestMappingInfo的信息直到找到匹配的requestMappingInfo

④:根據requestMappingInfomappingLookup中找到handlerMethod

handlerMethod接口如下:

技術分享

到這裏大家差不多就明白了吧,有了處理器實例,方法,參數調用反射執行方法分分鐘的事情

當然spring mvc真正執行比這個復雜的多啦,但是執行的時候是逃不出這個套路的。

具體的URL找到處理器Controller中相應方法的流程請大家看一下DispatcherServlet--getHandler()方法

註:

最後說一下RequestMappingHandlerMapping並不是默認的查找處理器方法的策略,他是通過 <mvc:annotation-driven />配置完成容器註冊的

Spring mvc之源碼 handlerMapping和handlerAdapter分析