SpringMvc源碼解析


最近公司這邊在考慮Api gateway,准備用zuul來實現,借此機會,把SpringMvc又了解了下

 

SpringMvc我相信大家都有用過,但SpringMvc的整個執行流程,不知道大家是否了解。今天主要是針對SpringMvc的執行流程及原理和大家做個分享。

 

首先,我們可以通過一張圖來了解SpringMvc的執行流程

 

 

 

任何一個框架,都有自己特定的適用領域,框架的設計和實現,必定是為了應付該領域內許多通用的,煩瑣的、基礎的工作而生。SpringMvc作為一個表現層框架,也必須直面Web開發領域中表現層中的幾大點:

 

1、URL到框架的映射

2、http請求參數綁定

3、http響應的生成和輸出

 

那SpringMvc到底是怎么完成以上所述的問題的呢?

 

下面我以一個Http請求流程,依次介紹SpringMvc整個執行流程,及相關核心接口與類:

 

用戶在瀏覽器中輸入http://www.xxx.com/abc/1的地址,回車后,瀏覽器發起一個http請求。請求到達服務器后,首先會被SpringMvc注冊在web.xml中的前端轉發器DispatcherServlet接收,DispatcherServlet是一個標准的servlet,它的作用是接受和轉發web請求到內部框架處理單元

 

我們先看一下DispatcherServlet,通過doService->doDispath()方法:

 

 

a、通過HttpServletRequest獲取一個HandlerMapping實現類

 

1、HandlerMaping

接下來,我們看下HandlerMapping接口

 

 

該接口只有唯一的一個方法,通過httpServletRequest獲取一個HandlerExecutionChain

 

回到DispatcherServlet的執行流程,當DispatcherServlet接收到web請求后,由servlet處理doGet或doPost方法,最終轉發到DispathcherServlet->doService方法(Spring在啟動時,會加載程序注入進去的所有HandlerMapping實現類)。以該web請求的HttpServletRequest對象為參數,依次調用其getHandler方法,第一個不為null的調用結果,將被返回。DispatcherServlet類中獲取handlerMapping方法如下:

 

 

到這,SpringMvc的第一步處理就完成了,一個Web請求經過處理后,會得到一個HandlerExecutionChain對象,這就是SpringMvc對URI映射的結果。HandlerMapping接口的getHandler方法參數是HttpServletRequest,這意味着,HandlerMapping的實現類可以利用HttpServletRequest中的 所有信息來做出這個HandlerExecutionChain對象的生成”決策“。這包括,請求頭、url路徑、cookie、session、參數等等一切你從一個web請求中可以得到的任何東西(最常用的是url路徑)。

 

HandlerMapping返回的是一個HandlerExecutionChain類,從名字上看是對執行鏈的封裝,接下來,我們看下HandlerExecutionChain定義

 

 

類較長,我只截取了參數列表,其實這里面最主要的也就是以下兩行:

 

一個實質的執行對象,還有一個攔截器列表

 

 

HandlerInterceptor定義如下:

 

 

至此,HandlerExecutionChain整個執行脈絡也就清楚了:在真正調用其handler對象前,HandlerInterceptor接口實現類組成的數組將會被遍歷,其preHandle方法會被依次調用,然后真正的handler對象將被調用。handler對象被調用后,就生成了需要的響應數據,在將處理結果寫到HttpServletResponse對象之前(SpringMVC稱為渲染視圖),其postHandle方法會被依次調用。視圖渲染完成后,最后afterCompletion方法會被依次調用,整個web請求的處理過程就結束了。

 

在一個處理對象執行之前,之后利用攔截器做文章,這已經成為一種經典的框架設計套路。Struts2中的攔截器會做諸如參數綁定這類復雜的工作,那么SpringMVC的攔截器具體做些什么呢?我們暫且不關心,雖然這是很重要的細節,但細節畢竟是細節,我們先來理解更重要的東西。

 

HandlerInterceptor,可以看出這是SpringMvc的一個暴露點,通過自定義攔截器,我們可以在一個請求被真正處理之前、請求被處理但還沒輸出到響應中、請求已經被輸出到響應中之后這三個時間點去做任何我們想要做的事情。

 

這個HandlerExecutionChain類中以Object引用所聲明的handler對象,到底是個什么東東?它是怎么被調用的?

 

在理解該問題之前,我們先看一下另一個核心類HandlerAdapter:

 

 

在DispatcherServlet中,除了HandlerMappingg列表,也有HandlerAdapter列表,如:

 

 

HandlerExecutionChain中的handler對象會被作為參數傳遞進去,在DispatcherServlet類中注冊的HandlerAdapter實現類列表會被遍歷,然后返回第一個supports方法返回true的HandlerAdapter對象,用這個HandlerAdapter實現類中的handle方法處理handler對象,並返回ModelAndView這個包含了視圖和數據的對象。HandlerAdapter就是SpringMVC提供的另一個擴展點,你可以提供自己的實現類來處理handler對象。

 

接下來,我們看下HandlerAdapter到底做了哪些事

進入到RequestMappingHandlerAdapter,找到invokeHandlerMethod方法,如下:

 

 

代碼中紅框框起來的地方是指:

1、根據handlerMethod和binderFactory創建一個ServletInvocableHandlerMethod。后續把請求直接交給ServletInvocableHandlerMethod執行。

2、createRequestMappingMethod方法比較簡單,把之前RequestMappingHandlerAdapter初始化的argumentResolvers和returnValueHandlers添加至ServletInvocableHandlerMethod中

 

啟動時,SpringMvc加載RequestMappingHandlerAdapter時,進初始化對應的參數轉換器:

 

 

 

剛剛看到invokeHandlerMethod方法,在創建ServletInvocableHandlerMethod,后調用invokeAndHandle方法

 

 

這里,我們主要看下invokeForRequest,從方法名可以看出,通過反射調用對應的HandleMethod對應的method方法

 

 

獲取參數中, 我們可以點進去看到,這里通過不同的參數注解,獲取到對應的實現類,來獲取參數信息

 

 

這里提個問題,如果是@RequestBody 和 @ResponseBody,SpringMvc又是怎么處理的呢?

有興趣的朋友,可以接着深入看看HttpMessageConverter

 

HandlerAdapter處理完成,接着我們回到DispatcherServlet-doDispathcer()方法:

 

 

接着執行我們的攔截器 postHandle方法

 

HandlerAdapter返回的ModleAndView對象,我們看下View接口定義

 

 

所有的數據,最后會作為一個Map對象傳遞到View實現類中的render方法,調用這個render方法,就完成了視圖到響應的渲染。這個View實現類,就是來自HandlerAdapter中的handle方法的返回結果。當然從ModelAndView到真正的View實現類有一個解析的過程,ModelAndView中可以有真正的視圖對象,也可以只是有一個視圖的名字,SpringMVC會負責將視圖名稱解析為真正的視圖對象。

 

至此,我們了解了一個典型的完整的web請求在SpringMVC中的處理過程和其中涉及到的核心類和接口。

 

在一個典型的SpringMVC調用中,HandlerExecutionChain中封裝handler對象就是用@Controller注解標識的類的一個實例,根據類級別和方法級別的@RequestMapping注解,由默認注冊的DefaultAnnotationHandlerMapping(3.1.3中更新為RequestMappingHandlerMapping類,但是為了向后兼容,DefaultAnnotationHandlerMapping也可以使用)生成HandlerExecutionChain對象,再由AnnotationMethodHandlerAdapter(3.1.3中更新為RequestMappingHandlerAdapter類,但是為了向后兼容,AnnotationMethodHandlerAdapter也可以使用)來執行這個HandlerExecutionChain對象,生成最終的ModelAndView對象后,再由具體的View對象的render方法渲染視圖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM