天天看點

SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例

springmvc處理靜态資源,主要是兩個标簽,mvc:resources和mvc:default-servlet-handler。在詳細說明他們的原理之前,需要先簡單說明下springmvc中請求處理機制:handlermapping和handleradapter。

用過python django架構的都知道django對于通路方式的配置就是,一個url路徑和一個函數配對,你通路這個url,就會直接調用這個函數,簡單明了

然而對于springmvc架構來說,由于java的面向對象,就要找到對應的類以及對應的方法,是以就需要分成2步走

第一步 先找到url對應的處理類,叫handler,這裡就用到handlermapping來尋找

第二步 找到了對應的handler之後,我們該調用這個handler的哪個方法呢?這就需要handleradapter來決定

根據request請求,找到對應的handlerexecutionchain,handlerexecutionchain是handler和攔截器的結合。如下:

即針對某個請求,會有對應的handler和攔截器來處理。handlermapping僅僅是找到對應的handler和攔截器罷了,它并不限制handler的類型,任何一個存在于spring的ioc容器中的bean都可以成為handler,是以這個handler是object。

下面來看下常見的幾個handlermapping實作:

beannameurlhandlermapping : 對url直接配置一個bean作為這個url的handler。如在xml中如下配置

當我們通路 http://localhost:8080/index 時,就直接找到這個bean作為handler。

simpleurlhandlermapping : 上述隻能配置一個url對應的bean,simpleurlhandlermapping就可以配置多個,功能上更強大,它内部有一個map urlmap,存放着各個url對應的handler,如下

根據handlermapping找到了handler之後,我們該調用handler的哪個方法呢?handler又有哪些方法呢?這裡就需要采用擴充卡的模式,對不同的handler進行不同的處理。是以handleradapter的supports方法首先判斷這個handler是否是我能支援的,如果能支援,那我就按照我的處理模式來處理,即調用上述的handle方法。

下面來看下常見的幾個handleradapter的實作:

simpleservlethandleradapter : 它支援的handler必須是servlet,這樣的話該handler就必然有service(request, response)方法,是以就會調用handler的service(request, response)方法來處理請求,源碼如下

simplecontrollerhandleradapter : 它支援的handler必須是controller,controller接口定義了一個modelandview handlerequest(httpservletrequest request, httpservletresponse response)方法,是以我們知道該handler必然有一個handlerequest方法,就調用它來處理請求,源碼如下

httprequesthandleradapter : 它支援的handler必須是httprequesthandler,httprequesthandler接口定義了一個void handlerequest(httpservletrequest request, httpservletresponse response)方法,是以就知道該調用這個handler的handlerequest方法,源碼如下:

接下來就輪到重點了(上面的鋪墊夠長的了,哈哈)

來看下一般的mvc:resources的使用,如下:

然後來看源碼。首先要再次聲明下,所有在xml中配置的标簽,都會有對應的beandefinitionparser的實作類來進行處理,對于mvc:resources标簽,對應的實作類是resourcesbeandefinitionparser,檢視其中的源碼(這裡不再列出,自行去檢視),可以知道

注冊了一個simpleurlhandlermapping(上文已提到)。它是擁有一個map urlmap的,它把mvc:resources标簽中的mapping屬性作為key,把resourcehttprequesthandler作為handler。即/css/**類似的url請求,會由這個simpleurlhandlermapping比對到resourcehttprequesthandler上。

再看下,到底調用resourcehttprequesthandler的哪個方法來處理請求呢?

resourcehttprequesthandler實作了httprequesthandler,即是上文提到的httprequesthandleradapter支援的handler類型,是以就會調用resourcehttprequesthandler的void handlerequest(httpservletrequest request, httpservletresponse response)方法

其實很容易就明白了,resourcehttprequesthandler會根據mvc:resources标簽中的location屬性作為目錄,去尋找對應的資源,然後傳回資源的内容。這裡就不再詳細說明了,可以自行檢視resourcehttprequesthandler的所實作的handlerequest方法。

同理,mvc:default-servlet-handler标簽對應的beandefinitionparser的實作類是defaultservlethandlerbeandefinitionparser。

這裡注冊了simpleurlhandlermapping,它的map urlmap中存放了一個 key為/* ,對應的handler為defaultservlethttprequesthandler。即請求路徑比對 / * 的時候,這個simpleurlhandlermapping會交給defaultservlethttprequesthandler來處理。這種情況一般是其他handlermapping無法比對處理,最後才無奈交給defaultservlethttprequesthandler。

來看下defaultservlethttprequesthandler是怎麼處理的:

它同樣實作了httprequesthandler接口,擁有void handlerequest(httpservletrequest request, httpservletresponse response)方法,如下:

我們可以看到,這裡其實就是轉發給了web容器自身的servlet。這個servlet名稱可以在mvc:default-servlet-handler标簽中進行配置,如果沒有配置,采用預設的配置,如下:

其實這個時候,請求先經過tomcat的servlet的url-pattern的比對,進入到了springmvc,然後經過springmvc的handlermapping的一系列比對,沒有對應的handler比對,導緻又再次轉發給tomcat等預設的servlet上了,繞了很大的彎,是以要盡量避免這樣的操作。

這裡舉一個案例進行分析,在tomcat釋出的根目錄中,有一個a.html和a.jsp檔案,以及一個springmvc項目,如下:

SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例

其中springmvc項目配置了mvc:default-servlet-handler标簽,接下來以springmvc的dispatcherservlet的兩種配置進行說明,分别是

結果分别是:

dispatcherservlet配置為 / 的時候,a.html和a.jsp都可以正常通路到,如下

SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例
SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例

dispatcherservlet配置為 /* 的時候,a.html可以正常通路到,a.jsp就不行了,如下

SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例
SpringMVC處理靜态檔案源碼分析1 HandlerMapping和HandlerAdapter的來由2 常用的HandlerMapping和HandlerAdapter簡單介紹3 mvc:resources源碼分析4 mvc:default-servlet-handler 源碼分析5 結合tomcat的url-pattern來綜合案例

分析如下:

通路a.html時:

當dispatcherservlet配置為 / 的時候,tomcat仍會選擇springmvc的dispatcherservlet來處理a.html-》它也處理不了,交給預設配置的mvc:default-servlet-handler來處理-》轉發到tomcat預設的servlet的,即defaultservlet來處理-》defaultservlet去尋找有沒有該檔案,找到了,傳回檔案内容

當dispatcherservlet配置為 /* 的時候,tomcat仍然是選擇springmvc的dispatcherservlet來處理a.html,同上面是一樣的過程

通路a.jsp時:

當dispatcherservlet配置為 / 的時候,tomcat會優先選擇自己已經預設注冊的jspservlet來處理-》jspservlet翻譯檔案内容,傳回

當dispatcherservlet配置為 /* 的時候,tomcat會選擇springmvc的dispatcherservlet來處理a.jsp-》發現springmvc找不到比對的handler,交給配置的mvc:default-servlet-handler來處理-》轉發到tomcat預設的servlet的,即defaultservlet來處理-》defaultservlet僅僅将a.jsp的源碼内容進行傳回