先抛出問題。以下兩個方法聲明有毛差別:
這是在一個controller裡面的接口方法聲明,這兩個方法,一個聲明了
另一個沒有,他們看似沒有差別,但是spring mvc的套路裡面,他們在特殊場景下的差別大的你想哭。
先描述問題的源頭:
某天刮風,飄來了一個接口需要處理
http://localhost:8088/1/2/rg.html
這個接口沒有什麼特殊,get請求,傳回json資料,由于習慣使用g.html而不是g.json,再為了相容jsonp,然而依賴@responsebody注解的方式,對jsonp支援不夠完美。
是以,方法g裡面,直接操作response,具體處理的地方是另一個地方,利用filter+threadlocal實作的,是以,在g方法中無需聲明httpservletresponse就能達到目的
這樣處理一下,接口也的确傳回了資料,但是reponse.status一直是500。問題描述完畢。
怎麼了,你累了,說好的200呢?
首先找到500的原因.
spring mvc裡面,我配置了根據用戶端的不同的請求決定不同的view進行響應的視圖解析器
實驗證明,如果我不配置這個解析器,頁面會直接404,其實這是同一個問題,是以我去掉這個解析器,頁面立即顯示了閃花眼鏡的tomcat404
看到錯誤資訊,加上404,聯想到/1/2/1/2/rg這個資源沒有找到,然而,我們本也沒打算給它配資源,get請求回去的,是json資料。
在dispaterserlvet的方法dodispatch中,modelandview被指派,利用這個入口,可以找到原因。
循序打入斷點,到了解析方法參數的地方。
如果mv為null,則不會去尋找資源,是以開始尋找這個void請求,為毛還傳回不為null的mv。
往下走,
org.springframework.web.servlet.mvc.method.annotation.requestmappinghandleradapter.invokehandlermethod中,調用getmodelandview
如果
為真,那麼我們就達到目的了。(我為什麼會這麼推測了,是以controller參數含response和不含response的情況下,我分别跟蹤了代碼。為什麼想到需要response參數呢,因為别人家的接口都正确傳回了200狀态,我家的為什麼不按套路,隻有對比了。)
往下走
org.springframework.web.servlet.mvc.method.annotation.servletinvocablehandlermethod.invokeandhandle中的判斷條件
這是請求controller層接口的實作方法,由于我們的rg方法是void傳回類型,是以,這裡的returnvalue是null,如果滿足
就好,而帶response參數的請求
為true。
最終
handlermethodargumentresolver.resolveargument(parameter, mavcontainer, webrequest, binderfactory);
隐藏了我們想要的真相。
對于參數response,他對應的方法參數解析器是
mavcontainer是modelandview的容器,裡面存放了很多資訊,這裡不深究了。
這裡
設定了請求已經被處理的辨別,這樣
就為真了。
最後帶了response參數的方法,最終傳回的modelandview為null,也就不會找到資源
/1/2/1/2/rg
也就不會出現404了。
總結
httpservletresponse httpservletresponse參數神奇的原因是因為
它做了特殊處理,帶上這個參數的接口,都會被認為請求已經被處理了。
在springmvc裡面,一個參數聲明與否,并不是等價的,即使你沒有用到,他也有存在的意義
新部落格位址:http://www.cnblogs.com/windliu