接上一篇-springmvc源碼分析開頭片
上一節主要說了一下springmvc與struts2的作為MVC中的C(controller)控制層的一些區別及兩者在作為控制層方面的一些優缺點。今天就結合下面的一張圖和上一篇中關於springmvc各個模塊之間及各個模塊中的類的繼承關系的一張圖對springmvc的請求處理流程進行一個分析。當然有了springmvc的請求處理流程我們就知道了springmvc是如何在啟動的時候去加載或者去解析對應的具體控制器,以及modleAndView使干什么用的,如何將controller處理后的結果映射到view中,也就是在我們java中的jsp或者freemaker中的。當然下面的這張圖可能很多網友也有,但是可能每個人根據這張圖的理解去分析的springmvc的原理都是不一樣的(我只是結合這兩張圖我自己的一個理解)好了廢話不多說咱們有圖才有說服力。。。

這張圖確實比較經典。首先我們大致的說一下:springmvc這個框架其實主要是有這幾個大的模塊組成的① dispatcherServlet ②handlerMapping③ controller④modelAndView⑤viewResolver⑥ view。當時這個springmvc的整個請求的流程不是加載的流程。對這個加載的流程做一個簡答的介紹
①:DispatcherServlet是springmvc中的前端控制器(front controller),負責接收request並將request轉發給對應的處理組件.
②:HanlerMapping是springmvc中完成url到controller映射的組件.DispatcherServlet接收request,然后從HandlerMapping查找處理request的controller.
③:Cntroller處理request,並返回ModelAndView對象,Controller是springmvc中負責處理request的組件(類似於struts2中的Action),ModelAndView是封裝結果視圖的組件.
④:視圖解析器解析ModelAndView對象並返回對應的視圖給客戶端.
⑤:viewResolve是對我們的每個具體實現的controller封裝后返回的modelAndView這個對象的解析處理,在這個根據我們配置的視圖解析器將對應的modelAndView映射到對應的view(jsp或者其他的顯示層語言)中去顯示我們controller處理后返回到視圖層的內容
⑥:顯示每個controller返回的視圖解析器的內容到對應的視圖給客戶端(view).
上面大致就是我們一個springnvc在發送一個get或者post的controller請求后再控制層的處理流程。
結合上面的請求處理流程,原本接下來應該是說一個在每個模塊中也就是每一步是如何做的,但是在這里我想先去說一下加載的過程,也就是我們知道我們在使用springmvc的時候有時候我們使用配置文件的形式來配置,有時候使用注解的方式,但是大多數時候換是會采用注解的方式,這也是springmvc與struts2相比可以實現百分百零配置的優勢所在。那么在我們不管是配置文件也好,是注解也好,我們知道springmvc的原生態的嵌入到我們的spring中的,那么在加載我們的spring文件的時候是如何加載springmvc的配置或者注解的呢?下面咱們從開始的地方來說一下:
首先大家不管是有沒有去看過springmvc的源碼,我想大家應該讀知道我們在發送一個springmvc請求的時候是根據一個請求的去springmvc容器中去找跟這個url對應的具體的處理controller是哪個,找到后就去做業務處理,做完業務處理后封裝一個modelandview 然后通知springmvc的viewResolve去對這個controller對應的modelAndView進行解析然后映射或者渲染到view中實現在客戶端(這里一般是瀏覽器)上顯示處理后的內容。但是這里我想大家都知道,那么springmvc的url和controller的對應關系是怎么建立的呢??
對於springmvc有了解的我想大家對spring也不陌生,因為springmvc原生態的支持spring。所以在spring啟動加載容器的時候,也會去加載springmvc對應的controller的配置文件或者說注解。在spring加載完所有的bean的時候,springmvc會去遍歷spring容器加載后的bean,然后根據我們的配置或者注解將controller上的url和對應的bean放到一個map中。這樣我們就可以根據request請求中的url快速的定位到我們具體要使用的那個controller。這時候我們就有了兩者的對應關系,但是這時候換需要我們去處理相關的參數信息。springmvc在處理參數信息的時候有兩種方式,一種是在使用了@requestParam這個注解的時候,springmvc可以直接去將參數中的值和requestParam注解的參數進行一個綁定。如果不是使用的顯示的注解方式,而是使用的根據參數名的方式映射綁定的話,那么springmvc在處理這樣的參數的時候是使用的其他的工具類asm。這是因為java在做類的反射的時候只提供了獲取方法參數類型的反射,並沒有獲取方法名的反射,因此這個時候springmvc在處理這個參數的綁定的時候,就使用asm的讀取字節碼的方式來獲取方法名(asm這玩意是個操作字節碼的框架,大家有興趣的話可以去研究一下)。在這里兩種方式跟大家說了,但是我要補充一下,如果你能使用注解的時候盡量使用注解,因為springmvc在使用asm框架去讀取字節碼的時候是很麻煩的也比較耗時,建議大家能使用@requestparam注解的盡量使用。
好了上面是對spring在加載springmvc相關控制器的時候是如何處理的做了一個大致的闡述。雖然不是很詳細,但是總算有了對springmvc這個框架的一個整體的了解,這個時候我們再去分模塊的去研究他。
下面先開始對dispatcherServlet的研究。
我們學過servlet的大家都知道,我們servlet的生命周期是 init() doservice(){doGet(),doPost()},doDestory().,我們看到dispatcherservlet的繼承關系是--》frameWorkServlet--》httpServletBean--》httpServlet。所以由這樣的繼承關系在加上servlet的生命周期,我們就可以知道,在tomcat容器在啟動加載的時候回去執行init().但是在這個init()中又回去調用子類的方法。這里我們截圖看一下。


結合上面的這兩幅圖,我簡單的做一個介紹。我們都知道servlet的生命周期開始於init()所以在加載容器的時候當然也是要從init開始,所以我就從dispatcherServlet最上層的實現類開始找,知道找到httpBeanServlet,然后再看他的父類httpservlet,httpservlet的父類genericServlet,最后是實現的一個servlet的接口。我從servlet的接口中找到了容器最開始加載的init()這個方法。這個時候我們去看genericServlet的時候發現只是對接口中的init方法進行了一個實現 但是具體的實現內容沒有去做。我們再去看httpServlet這個繼承了genericServlet的抽象類中沒有init()這個方法。這個時候我們再去httpbeanServlet中發現了一個唄定義為final類型的init()方法。我們知道final類型的方法是不能被子類繼承的,好了到這里我們終於找到了加載開始的入口。
----------今天我們找到了門,明天我們進門去一探究竟。明天晚上見^_^
