springMVC處理一個請求的過程-源碼詳解


貼上我們用來測試的代碼:
在這裏插入圖片描述
很簡單,就是一個註解的controller,只要從瀏覽器輸入對應的路徑,這個方法就會攔截這個請求,進而開始具體的處理

1.springMVC如何尋找對應的controller?

我們先列出大概的流程,之後會進行詳解

在這裏插入圖片描述
springmvc中最重要的就是前端處理器,也就是DispatcherServlet了,它會攔截瀏覽器的請求進行轉發,交給對應的controller進行處理,首先它是一個繼承自httpServlet的Servlet,而httpServlet中有三個重要的方法doGet,doPost,Service,可以看一下這篇文章:Servlet詳解
找到DispatcherServletdoGetdoPost方法,這兩個方法都調用了
在這裏插入圖片描述
這個方法,爲了節省篇幅,我們直接找到裏面的doService方法,這個方法又調用了doDispatch方法,doDispatch是我們研究的重點,我們所謂的視圖解析,數據封裝,方法處理基本都在這個方法中進行,在具體探討之前,我們先列出一個springmvc處理的大概流程

  • 首先掃描整個項目,也就是我們定義的包掃描的範圍,拿到所有加了@Controller註解的類,並且定義一個map集合
  • 將加了@Controller註解的類中的方法進行遍歷
  • 判斷這些類中的方法是否被加了@RequestMapping註解
  • 如果有註解,就將其註解的value作爲key加入map,它的value就是該方法對象
  • 根據用戶發送的請求,拿到URI
  • 根據這個URI作爲key去map中匹配,看是否有返回值,如果有就匹配與之對應的適配器,然後再進行處理…

下面我們就根據源代碼來看看是否是這個過程,需要注意的是,我們看源碼並不需要一行行的看懂,我個人認爲看源碼的目的是看裏面的設計模式,設計思想和如何完成功能,所以文章剩下部分的代碼可能有的地方不會着重介紹

2.將method封裝到map中

在這裏插入圖片描述
mappedHandler顧名思義就是處理器映射器,它是一個HandlerExecutionChain對象,這個對象是來做什麼的呢?首先這個對象是由HandlerMapping創建的HandlerMapping是獲取所有請求與處理器(爲了大家好理解,我們將處理器理解爲Handler也就是常說的控制器Controller)的關係,而HandlerExecutionChain代表具體某一個處理器與請求的關係,其中可能包括攔截器,我們進入這個方法:
在這裏插入圖片描述
注意這裏的private List<HandlerMapping> handlerMappings;它有多種HandlerMapping:
在這裏插入圖片描述
爲什麼會有這兩種HandlerMapping來創建我們的mappedHandler呢?原因是因爲我們創建controller的方式不同,現在絕大部分創建的方式就是加上Controller註解,但是還有其他方式:
在這裏插入圖片描述
在這裏插入圖片描述
即通過接口的方式創建,所以要根據不同創建方式來創建不同的HandlerExecutionChain對象,我們接着getHandler方法往下走,發現了HandlerExecutionChain handler = hm.getHandler(request);這行代碼,我們進入這個getHandler方法:
在這裏插入圖片描述
再次進入標記的方法:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
代碼到這裏我們可以發現,這個邏輯確實是根據URI路徑去map匹配我們對應的方法!

2.適配器處理

程序執行到這裏,已經拿到了我們所需要的方法了:
在這裏插入圖片描述
接下來就是根據傳進去的method方法去匹配對應的適配器了,爲什麼需要不同的適配器,是因爲執行的方法不同,如果是註解方式,對應controller通過反射來調用方法,如果是實現接口的處理器,則調用接口的實現類來調用方法,我們進入這個方法:
在這裏插入圖片描述
我們可以看看都有哪些適配器:
在這裏插入圖片描述
進入這個supports判斷邏輯,我們這裏是通過註解註冊的Controller,因此是這種:
在這裏插入圖片描述

3.處理Handler的參數

獲取到適配器之後就可以處理這個方法了,返回一個ModelAndView mv對象:
在這裏插入圖片描述
我們進入這個方法
在這裏插入圖片描述
在這裏插入圖片描述
進入invokeHandlerMethod方法,找到這一行:
在這裏插入圖片描述
然後進入這個方法:
在這裏插入圖片描述
這就是重點代碼了:
在這裏插入圖片描述
我們的請求參數中經常會攜帶一些參數,適配器對參數的處理可謂是重中之重,第一個標紅的代碼表示獲取傳入方法的參數,springmvc會自動的將傳入的參數封裝成相應的對象,前提是方法參數中是對象,根據路徑傳進來的參數來解析封裝對象,要是我們,該怎麼處理這些參數呢?通過註解的Controller會通過反射創建方法對象進行參數的處理,我們寫一段僞代碼來看看:
在這裏插入圖片描述
這就是處理參數的一個大概過程,下面我們通過源代碼來驗證

4.參數處理細節

在這裏插入圖片描述
進入第一個方框的代碼:
在這裏插入圖片描述
和我們的僞代碼類似,它會先判斷參數的類型,去請求中獲取對應參數類型的值,不過和我們普通的if判斷不同,這裏是通過參數處理器來進行判斷的,也就是argumentResolvers

private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();

其中:HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver,故HandlerMethodArgumentResolver就是我們說的參數處理器
我們可以看一下有多少種參數處理器:
在這裏插入圖片描述
有27種不同的參數處理器,如果通過我們簡單的if elsel判斷,那麼代碼就會變得非常冗餘,進入下面給args數組賦值的代碼中:

args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
							

在這裏插入圖片描述
它先獲取了參數處理器,進入這個方法:
在這裏插入圖片描述
我們通過瀏覽器訪問首先不會進入緩存,不進入緩存,就會進入到
if (methodArgumentResolver.supportsParameter(parameter))這個判斷種,也就是根據參數選擇合適的參數處理器,並將這個參數處理器放進緩存中,下次就直接從緩存種得到參數處理器去給參數賦值,給參數賦值過後就可以真正處理參數了:

return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);

處理過程就是我們自己寫的邏輯代碼

總結:

這裏僅僅是簡單介紹了springmvc是如何通過請求去匹配到對應的controller來處理請求,並且處理請求參數,至於如何解析視圖,由於篇幅原因,請看另一篇文章:
spring MVC如何解析視圖,View視圖源碼解析
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章