SpringtMVC運行流程:@RequestMapping 方法中的 Map、HttpServletRequest等參數信息是如何封裝和傳遞的(源碼理解)


在平時開發SpringtMVC程序時,在Controller的方法上,通常會傳入如Map、HttpServletRequest類型的參數,並且可以方便地向里面添加數據。同時,在Jsp中還可以直接使用request等對象方便地獲取出來。

如下面2圖所示:

 

可問題是:@RequestMapping 方法中的 Map、HttpServletRequest等參數信息是如何封裝和傳遞的?

帶着這個問題,寫了個簡單的Demo,來進行源碼調試。

Demo代碼地址:

https://github.com/cyhbyw/springMVC_atguigu_TongGang

工程名稱:

springMVC_DebugSourceCode

 

===========以下是源碼調試==================

==============>>>>
PS:圖片可能不是很清晰,可以右擊圖片、選擇在新標簽頁中查看
或者,可以右擊圖片,選擇“圖片另存為”保存在本地並編好號(建議直接以01、02、03……來編號)
或者,可以右擊圖片,選擇“復制圖片”,再保存到本地並編好號(建議直接以01、02、03……來編號)
以上三種辦法,任意選擇喜歡的一種,以獲得並查看更清晰的圖片~~
<<<<==============

01.首先,瀏覽器發出的請求到DispatcherServlet;然后,找到合適的HandlerAdapter(此處是RequestMappingHandlerAdapter);然后調用RequestMappingHandlerAdapter的handle()方法。此時,方法堆棧從Line959開始。

 

  

02.還是在DispatcherServlet的Line959的doDispatch()方法內,又調用了幾個方法,到達invokeForRequest()方法;顧名思義,此方法會真正的調用Request方法(即Controller中的方法);不過,先會在Line128解析參數。

 

 

 03.解析參數的方法又會走到Line161.

 

 

 04.再經過兩個方法的調用,可以看到上述的參數解析方法是直接返回了 mavContainer.getModle()

而由06步可以看到,Model實際上是個map對象,那么,此處直接返回map對象就相當於返回了其引用,外部任何地方的修改都將影響此map中的值!!!

這個引用會給第08步中的 Object[] args 以及第09、10步中的 map,所以第10步中向 map 中添加數據,其實也就等價於向此 Model 中添加了數據!!!(背景知識:Java對象引用)

 

  

05.而getModel() 方法返回 defaulutModel 的成員變量。

 

  

06. defaulutModel 其實就是一個 BindingAwareModelMap

 

 

 07.回到剛才的Line161,可以看到 args[i] 指向了剛才得到的BindingAwareModelMap@4821。

 

  

08.再返回一層,此處的 Object[] args 還是BindingAwareModelMap@4821;並且到目前為止,其中的元素仍然為空;此處Line136的 doInvoke(args) 方法就是通過反射調用真實的Controller中的方法。

 

  

09.調用真實方法(由08步中的Line136反射調用);可以看到,真實Controller方法中的入參 map 還是BindingAwareModelMap@4821(說明是同一個對象——非常重要!!)

 

 

10.將值寫入map中

 

 

11.真實Controller方法調用返回后,可以看到 mavContainer 對象中的 defaultModel 屬性已經被賦值,且這個值就是BindingAwareModelMap@4821,與args是同一個對象(非常重要,而且從前面的分析中也可以看到)!!!!

(備注:SpringMVC是如何為mavContainer 對象中的 defaultModel 屬性賦值的,最開始調試了很久也沒有發現,心想着,它既然是個Map,那應該是調用setXXX(), put(), putAll()這樣的方法賦值進去的,但調試了很久始終沒發現這樣的方法被調用;同時,也可以確定它是在Line136行調用后就被賦值的;最后猜測,是同一個對象引用;現在,證明確實如此)

再啰嗦一句,其實就是:Line128的 Object[] args 變量指向了 mavContainer 對象的 defaultModel 屬性!所以在將 args 通過Line136反射調用真實的Controller方法並填充數據后,defaultModel中也就有了相應數據!

注意結合第04步中的文字進行理解!

 

 12.真實Controller方法調用完成后,開始處理返回值

 

 13.設置視圖名稱

 

 

 14.准備創建ModelAndView對象

 

  

15.從 mavContainer 中取出Model數據,並通過構造函數傳入ModelAndView

 

  

16.已經獲得ModelAndView對象,進行后續操作(如渲染);注意,此時DispatcherServlet中的方法堆棧從Line971開始。

 

  

17.准備渲染

 

  

18.得到View對象

 

  

19.遍歷 viewResolvers 找到一個合適的就返回給18步中的View對象

 

  

20.准備渲染

 

  

21.將Model數據暴露為RequestAttribute

 

  

22.暴露的本質其實是:request.setAttribute(modelName, modelValue)

重要:在這里是 request.setAttribute 所以在 Jsp 中才可以 request.getAttribute,先有 set 才有 get 嘛。

 

  

23.最后是一個轉發操作

 

 


免責聲明!

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



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