天天看點

SpringMVC源碼總結(九)HandlerMethodArgumentResolver介紹

本文章主要介紹handlermethodargumentresolver在springmvc中的使用,介紹幾個handlermethodargumentresolver具體的使用情況,然後說明handlermethodargumentresolver的注冊來源以及如何自定義注冊。 

首先具體看下請求映射到的handler的對應的映射函數的參數形式有哪些: 

handlermethodargumentresolver接口隻有兩個方法: 

<a href="http://my.oschina.net/pingpangkuangmo/blog/376343#">?</a>

1

2

3

4

5

<code>//判斷是否支援要轉換的參數類型</code>

<code>boolean</code> <code>supportsparameter(methodparameter parameter);</code>

<code>//當支援後進行相應的轉換</code>

<code>object resolveargument(methodparameter parameter, modelandviewcontainer mavcontainer,</code>

<code>            </code><code>nativewebrequest webrequest, webdatabinderfactory binderfactory)</code><code>throws</code> <code>exception;</code>

handlermethodargumentresolver接口的抽象類:abstractmessageconvertermethodargumentresolver僅僅引入了httpmessageconverter,即轉換的工作有這些httpmessageconverter來完成具體的轉換和判斷由子類來實作。 

如下: 

6

7

8

9

<code>public</code> <code>abstract</code> <code>class</code> <code>abstractmessageconvertermethodargumentresolver</code><code>implements</code> <code>handlermethodargumentresolver {</code>

<code>    </code><code>protected</code> <code>final</code> <code>log logger = logfactory.getlog(getclass());</code>

<code>    </code><code>protected</code> <code>final</code> <code>list&lt;httpmessageconverter&lt;?&gt;&gt; messageconverters;</code>

<code>    </code><code>protected</code> <code>final</code> <code>list&lt;mediatype&gt; allsupportedmediatypes;</code>

<code>     </code><code>//略</code>

<code>}</code>

abstractmessageconvertermethodargumentresolver 的抽象子類abstractmessageconvertermethodprocessor僅僅是加入了對響應資料進行轉換的支援。 

也就是abstractmessageconvertermethodprocessor的子類不僅可以用來轉換請求資料,也可以用來轉換響應資料。 

abstractmessageconvertermethodprocessor的子類httpentitymethodprocessor,支援請求和響應的轉換,代碼如下: 

<code>@override</code>

<code>    </code><code>public</code> <code>boolean</code> <code>supportsparameter(methodparameter parameter) {</code>

<code>        </code><code>return</code> <code>httpentity.</code><code>class</code><code>.equals(parameter.getparametertype());</code>

<code>    </code><code>}</code>

<code>    </code><code>@override</code>

<code>    </code><code>public</code> <code>boolean</code> <code>supportsreturntype(methodparameter returntype) {</code>

<code>        </code><code>return</code> <code>httpentity.</code><code>class</code><code>.isassignablefrom(returntype.getparametertype());</code>

使用場景如下: 

10

11

<code>@requestmapping</code><code>(value=</code><code>"/test/http"</code><code>,method=requestmethod.post)</code>

<code>    </code><code>@responsebody</code>

<code>    </code><code>public</code> <code>map&lt;string,object&gt; testhttp(httpentity&lt;string&gt; httpentity)</code>

<code>            </code><code>//略</code>

<code>        </code><code>}</code>

<code>@requestmapping</code><code>(value=</code><code>"/test/httpentity"</code><code>,method=requestmethod.get)</code>

<code>    </code><code>public</code> <code>httpentity&lt;string&gt; testhttpentity(){</code>

<code>        </code><code>//略</code>

abstractmessageconvertermethodprocessor的子類requestresponsebodymethodprocessor:支援@requestbody和@responsebody,代碼如下: 

12

13

<code>               </code><code>//查找參數中是否含有@requestbody注解</code>

<code>        </code><code>return</code> <code>parameter.hasparameterannotation(requestbody.</code><code>class</code><code>);</code>

<code>//查找參數中是否含有@requestbody注解或者controller類上是否含有@requestbody</code>

<code>        </code><code>return</code> <code>((annotationutils.findannotation(returntype.getcontainingclass(), responsebody.</code><code>class</code><code>) !=</code><code>null</code><code>) ||</code>

<code>                </code><code>(returntype.getmethodannotation(responsebody.</code><code>class</code><code>) !=</code><code>null</code><code>));</code>

<code>@requestmapping</code><code>(value=</code><code>"/test/requestbody"</code><code>,method=requestmethod.post)</code>

<code>    </code><code>public</code> <code>map&lt;string,object&gt; testrequestbody(</code><code>@requestbody</code> <code>map&lt;string,object&gt; map1){</code>

<code>        </code><code>map&lt;string,object&gt; map=</code><code>new</code> <code>hashmap&lt;string,object&gt;();</code>

<code>        </code><code>map.put(</code><code>"name"</code><code>,</code><code>"lg"</code><code>);</code>

<code>        </code><code>map.put(</code><code>"age"</code><code>,</code><code>23</code><code>);</code>

<code>        </code><code>map.put(</code><code>"date"</code><code>,</code><code>new</code> <code>date());</code>

<code>        </code><code>return</code> <code>map;</code>

httpentitymethodprocessor具體的解析參數的過程: 

<code>    </code><code>public</code> <code>object resolveargument(methodparameter parameter, modelandviewcontainer mavcontainer,</code>

<code>            </code><code>nativewebrequest webrequest, webdatabinderfactory binderfactory)</code>

<code>            </code><code>throws</code> <code>ioexception, httpmediatypenotsupportedexception {</code>

<code>        </code><code>httpinputmessage inputmessage = createinputmessage(webrequest);</code>

<code>        </code><code>type paramtype = gethttpentitytype(parameter);</code>

<code>        </code><code>object body = readwithmessageconverters(webrequest, parameter, paramtype);</code>

<code>        </code><code>return</code> <code>new</code> <code>httpentity&lt;object&gt;(body, inputmessage.getheaders());</code>

就是通過httpmessageconverter來進一步的判斷是否支援httpentity&lt;t&gt;中我們想要的t類型以及是否支援相應的content-type,如public map&lt;string,object&gt; testhttp(httpentity&lt;string&gt; httpentity) ,則會選擇stringhttpmessageconverter來進行轉換。具體的選擇過程如下: 

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

<code>protected</code> <code>&lt;t&gt; object readwithmessageconverters(httpinputmessage inputmessage,</code>

<code>            </code><code>methodparameter methodparam, type targettype)</code><code>throws</code> <code>ioexception, httpmediatypenotsupportedexception {</code>

<code>        </code><code>mediatype contenttype;</code>

<code>        </code><code>try</code> <code>{</code>

<code>            </code><code>contenttype = inputmessage.getheaders().getcontenttype();</code>

<code>        </code><code>catch</code> <code>(invalidmediatypeexception ex) {</code>

<code>            </code><code>throw</code> <code>new</code> <code>httpmediatypenotsupportedexception(ex.getmessage());</code>

<code>        </code><code>if</code> <code>(contenttype ==</code><code>null</code><code>) {</code>

<code>            </code><code>contenttype = mediatype.application_octet_stream;</code>

<code>        </code><code>class&lt;?&gt; contextclass = methodparam.getcontainingclass();</code>

<code>        </code><code>for</code> <code>(httpmessageconverter&lt;?&gt; converter :</code><code>this</code><code>.messageconverters) {</code>

<code>            </code><code>if</code> <code>(converter</code><code>instanceof</code> <code>generichttpmessageconverter) {</code>

<code>                </code><code>generichttpmessageconverter&lt;?&gt; genericconverter = (generichttpmessageconverter&lt;?&gt;) converter;</code>

<code>                </code><code>if</code> <code>(genericconverter.canread(targettype, contextclass, contenttype)) {</code>

<code>                    </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                        </code><code>logger.debug(</code><code>"reading ["</code> <code>+ targettype +</code><code>"] as \""</code> <code>+</code>

<code>                                </code><code>contenttype +</code><code>"\" using ["</code> <code>+ converter +</code><code>"]"</code><code>);</code>

<code>                    </code><code>}</code>

<code>                    </code><code>return</code> <code>genericconverter.read(targettype, contextclass, inputmessage);</code>

<code>                </code><code>}</code>

<code>            </code><code>}</code>

<code>            </code><code>class&lt;t&gt; targetclass = (class&lt;t&gt;)</code>

<code>                    </code><code>resolvabletype.formethodparameter(methodparam, targettype).resolve(object.</code><code>class</code><code>);</code>

<code>            </code><code>if</code> <code>(converter.canread(targetclass, contenttype)) {</code>

<code>                </code><code>if</code> <code>(logger.isdebugenabled()) {</code>

<code>                    </code><code>logger.debug(</code><code>"reading ["</code> <code>+ targetclass.getname() +</code><code>"] as \""</code> <code>+</code>

<code>                            </code><code>contenttype +</code><code>"\" using ["</code> <code>+ converter +</code><code>"]"</code><code>);</code>

<code>                </code><code>return</code> <code>((httpmessageconverter&lt;t&gt;) converter).read(targetclass, inputmessage);</code>

<code>        </code><code>throw</code> <code>new</code> <code>httpmediatypenotsupportedexception(contenttype,</code><code>this</code><code>.allsupportedmediatypes);</code>

同理requestresponsebodymethodprocessor也會使用相應的httpmessageconverter來進行轉換。如public map&lt;string,object&gt; testrequestbody(@requestbody map&lt;string,object&gt; map1)則會選擇mappingjackson2httpmessageconverter或者mappingjacksonhttpmessageconverter來完成轉換。 

再看看另一類的handlermethodargumentresolver: 

requestparammethodargumentresolver支援的類型有,一種是含@requestparam注解的參數,另一種就是簡單類型,如integer、string、date、uri, url,locale等: 

源代碼如下: 

<code>public</code> <code>boolean</code> <code>supportsparameter(methodparameter parameter) {</code>

<code>        </code><code>class&lt;?&gt; paramtype = parameter.getparametertype();</code>

<code>        </code><code>if</code> <code>(parameter.hasparameterannotation(requestparam.</code><code>class</code><code>)) {</code>

<code>            </code><code>if</code> <code>(map.</code><code>class</code><code>.isassignablefrom(paramtype)) {</code>

<code>                </code><code>string paramname = parameter.getparameterannotation(requestparam.</code><code>class</code><code>).value();</code>

<code>                </code><code>return</code> <code>stringutils.hastext(paramname);</code>

<code>            </code><code>else</code> <code>{</code>

<code>                </code><code>return</code> <code>true</code><code>;</code>

<code>        </code><code>else</code> <code>{</code>

<code>            </code><code>if</code> <code>(parameter.hasparameterannotation(requestpart.</code><code>class</code><code>)) {</code>

<code>                </code><code>return</code> <code>false</code><code>;</code>

<code>            </code><code>else</code> <code>if</code> <code>(multipartfile.</code><code>class</code><code>.equals(paramtype) ||</code><code>"javax.servlet.http.part"</code><code>.equals(paramtype.getname())) {</code>

<code>            </code><code>else</code> <code>if</code> <code>(</code><code>this</code><code>.usedefaultresolution) {</code>

<code>                </code><code>return</code> <code>beanutils.issimpleproperty(paramtype);</code>

beanutils.issimpleproperty(paramtype)判斷是否是簡單類型的具體内容如下: 

<code>/**</code>

<code>     </code><code>* check if the given type represents a "simple" property:</code>

<code>     </code><code>* a primitive, a string or other charsequence, a number, a date,</code>

<code>     </code><code>* a uri, a url, a locale, a class, or a corresponding array.</code>

<code>     </code><code>* &lt;p&gt;used to determine properties to check for a "simple" dependency-check.</code>

<code>     </code><code>* @param clazz the type to check</code>

<code>     </code><code>* @return whether the given type represents a "simple" property</code>

<code>     </code><code>* @see org.springframework.beans.factory.support.rootbeandefinition#dependency_check_simple</code>

<code>     </code><code>* @see org.springframework.beans.factory.support.abstractautowirecapablebeanfactory#checkdependencies</code>

<code>     </code><code>*/</code>

<code>    </code><code>public</code> <code>static</code> <code>boolean</code> <code>issimpleproperty(class&lt;?&gt; clazz) {</code>

<code>        </code><code>assert.notnull(clazz,</code><code>"class must not be null"</code><code>);</code>

<code>        </code><code>return</code> <code>issimplevaluetype(clazz) || (clazz.isarray() &amp;&amp; issimplevaluetype(clazz.getcomponenttype()));</code>

<code>public</code> <code>static</code> <code>boolean</code> <code>issimplevaluetype(class&lt;?&gt; clazz) {</code>

<code>        </code><code>return</code> <code>classutils.isprimitiveorwrapper(clazz) || clazz.isenum() ||</code>

<code>                </code><code>charsequence.</code><code>class</code><code>.isassignablefrom(clazz) ||</code>

<code>                </code><code>number.</code><code>class</code><code>.isassignablefrom(clazz) ||</code>

<code>                </code><code>date.</code><code>class</code><code>.isassignablefrom(clazz) ||</code>

<code>                </code><code>clazz.equals(uri.</code><code>class</code><code>) || clazz.equals(url.</code><code>class</code><code>) ||</code>

<code>                </code><code>clazz.equals(locale.</code><code>class</code><code>) || clazz.equals(class.</code><code>class</code><code>);</code>

即當請求為 http://localhost:8080/test?name=abc時,處理函數若為test(string name),則對name的解析就是采用requestparammethodargumentresolver來解析的。 

requestheadermethodargumentresolver:主要用來處理含有@requestheader注解的參數,但同時該參數又不是map類型。如下: 

<code>        </code><code>return</code> <code>parameter.hasparameterannotation(requestheader.</code><code>class</code><code>)</code>

<code>                </code><code>&amp;&amp; !map.</code><code>class</code><code>.isassignablefrom(parameter.getparametertype());</code>

<code>    </code><code>protected</code> <code>object resolvename(string name, methodparameter parameter, nativewebrequest request)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>string[] headervalues = request.getheadervalues(name);</code>

<code>        </code><code>if</code> <code>(headervalues !=</code><code>null</code><code>) {</code>

<code>            </code><code>return</code> <code>(headervalues.length ==</code><code>1</code> <code>? headervalues[</code><code>0</code><code>] : headervalues);</code>

<code>            </code><code>return</code> <code>null</code><code>;</code>

源代碼已經說明的很明白了。 

使用場景: 

<code>@requestmapping</code><code>(value=</code><code>"/test/requestheader"</code><code>,method=requestmethod.get)</code>

<code>    </code><code>public</code> <code>map&lt;string,object&gt; testrequestheader(</code><code>@requestheader</code> <code>string  accept){</code>

若想擷取所有的header資訊:則使用另一個requestheadermapmethodargumentresolver,它則用來擷取所有的header資訊: 

41

42

43

44

<code>public</code> <code>class</code> <code>requestheadermapmethodargumentresolver</code><code>implements</code> <code>handlermethodargumentresolver {</code>

<code>//這裡已經寫明白了,要求參數必須含有@requestheader注解,并且是map類型</code>

<code>                </code><code>&amp;&amp; map.</code><code>class</code><code>.isassignablefrom(parameter.getparametertype());</code>

<code>    </code><code>public</code> <code>object resolveargument(</code>

<code>            </code><code>methodparameter parameter, modelandviewcontainer mavcontainer,</code>

<code>            </code><code>throws</code> <code>exception {</code>

<code>        </code><code>if</code> <code>(multivaluemap.</code><code>class</code><code>.isassignablefrom(paramtype)) {</code>

<code>            </code><code>multivaluemap&lt;string, string&gt; result;</code>

<code>            </code><code>if</code> <code>(httpheaders.</code><code>class</code><code>.isassignablefrom(paramtype)) {</code>

<code>                </code><code>result =</code><code>new</code> <code>httpheaders();</code>

<code>                </code><code>result =</code><code>new</code> <code>linkedmultivaluemap&lt;string, string&gt;();</code>

<code>            </code><code>for</code> <code>(iterator&lt;string&gt; iterator = webrequest.getheadernames(); iterator.hasnext();) {</code>

<code>                </code><code>string headername = iterator.next();</code>

<code>                </code><code>for</code> <code>(string headervalue : webrequest.getheadervalues(headername)) {</code>

<code>                    </code><code>result.add(headername, headervalue);</code>

<code>            </code><code>return</code> <code>result;</code>

<code>            </code><code>map&lt;string, string&gt; result =</code><code>new</code> <code>linkedhashmap&lt;string, string&gt;();</code>

<code>                </code><code>string headervalue = webrequest.getheader(headername);</code>

<code>                </code><code>result.put(headername, headervalue);</code>

從上面的解析過程可以看出,參數類型可以是普通的map類型,也可以是multivaluemap或者進一步的httpheaders,他們與普通map類型的差別是他們對value值後者們是以list形式存放,前者是以string形式存放。 

<code>    </code><code>public</code> <code>map&lt;string,object&gt; testrequestheader(</code><code>@requestheader</code> <code>map&lt;string,object&gt; map1){</code>

<code>public</code> <code>map&lt;string,object&gt; testrequestheader(</code><code>@requestheader</code> <code>multivaluemap&lt;string,object&gt; map1){</code>

pathvariablemethodargumentresolver:主要針對含有@pathvariable的參數,代碼如下: 

<code>        </code><code>if</code> <code>(!parameter.hasparameterannotation(pathvariable.</code><code>class</code><code>)) {</code>

<code>            </code><code>return</code> <code>false</code><code>;</code>

<code>        </code><code>if</code> <code>(map.</code><code>class</code><code>.isassignablefrom(parameter.getparametertype())) {</code>

<code>            </code><code>string paramname = parameter.getparameterannotation(pathvariable.</code><code>class</code><code>).value();</code>

<code>            </code><code>return</code> <code>stringutils.hastext(paramname);</code>

<code>        </code><code>return</code> <code>true</code><code>;</code>

<code>    </code><code>@suppresswarnings</code><code>(</code><code>"unchecked"</code><code>)</code>

<code>        </code><code>map&lt;string, string&gt; uritemplatevars =</code>

<code>            </code><code>(map&lt;string, string&gt;) request.getattribute(</code>

<code>                    </code><code>handlermapping.uri_template_variables_attribute, requestattributes.scope_request);</code>

<code>        </code><code>return</code> <code>(uritemplatevars !=</code><code>null</code><code>) ? uritemplatevars.get(name) :</code><code>null</code><code>;</code>

對于支援的類型也說明的很詳細。首先必須含有@pathvariable注解,其次如果是map類型,必須要指定@pathvariable的值,即這個

argumentresolver隻能擷取一個uri變量。要想擷取多個則要使用pathvariablemapmethodargumentresolver: 

<code>        </code><code>pathvariable annot = parameter.getparameterannotation(pathvariable.</code><code>class</code><code>);</code>

<code>        </code><code>return</code> <code>((annot !=</code><code>null</code><code>) &amp;&amp; (map.</code><code>class</code><code>.isassignablefrom(parameter.getparametertype()))</code>

<code>                </code><code>&amp;&amp; (!stringutils.hastext(annot.value())));</code>

<code>public</code> <code>object resolveargument(methodparameter parameter, modelandviewcontainer mavcontainer,</code>

<code>            </code><code>nativewebrequest webrequest, webdatabinderfactory binderfactory)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>@suppresswarnings</code><code>(</code><code>"unchecked"</code><code>)</code>

<code>                </code><code>(map&lt;string, string&gt;) webrequest.getattribute(</code>

<code>                        </code><code>handlermapping.uri_template_variables_attribute, requestattributes.scope_request);</code>

<code>        </code><code>if</code> <code>(!collectionutils.isempty(uritemplatevars)) {</code>

<code>            </code><code>return</code> <code>new</code> <code>linkedhashmap&lt;string, string&gt;(uritemplatevars);</code>

<code>            </code><code>return</code> <code>collections.emptymap();</code>

它要求必須含有@pathvariable注解,并且必須是map類型,并且@pathvariable注解的value沒有值。同時我們可以從pathvariablemapmethodargumentresolver和pathvariablemethodargumentresolver上面看出,他們的取值都是從request的屬性上進行擷取的webrequest.getattribute( 

handlermapping.uri_template_variables_attribute, requestattributes.scope_request);也就是說,在解析完@requestmapping比對工作後,便将這些參數設定進request的屬性上,屬性名為handlermapping.uri_template_variables_attribute。其他的handlermethodargumentresolver可以自行研究,這裡不再說明。 

至此,我們就要說明下handlermethodargumentresolver的注冊來源: 

它的來源分為兩部分,一部分spring預設的handlermethodargumentresolver,另一部分就是我們自定義的handlermethodargumentresolver。 

還是先看mvc:annotation-driven中配置自定義的handlermethodargumentresolver: 

<code>&lt;mvc:annotation-driven &gt;</code>

<code>        </code><code>&lt;mvc:argument-resolvers&gt;</code>

<code>            </code><code>&lt;bean</code><code>class</code><code>=</code><code>"xxx"</code><code>&gt;&lt;/bean&gt;</code>

<code>        </code><code>&lt;/mvc:argument-resolvers&gt;</code>

<code>    </code><code>&lt;/mvc:annotation-driven&gt;</code>

在mvc:argument-resolvers标簽下配置相應的自定義的handlermethodargumentresolver。 

然後在mvc:annotation-driven的注解驅動類annotationdrivenbeandefinitionparser中會有這樣的代碼: 

<code>managedlist&lt;?&gt; argumentresolvers = getargumentresolvers(element, parsercontext);</code>

<code>//略</code>

<code>if</code> <code>(argumentresolvers !=</code><code>null</code><code>) {</code>

<code>            </code><code>handleradapterdef.getpropertyvalues().add(</code><code>"customargumentresolvers"</code><code>, argumentresolvers);</code>

其中getargumentresolvers就是擷取我們自定義的handlermethodargumentresolver 

<code>private</code> <code>managedlist&lt;?&gt; getargumentresolvers(element element, parsercontext parsercontext) {</code>

<code>        </code><code>element resolverselement = domutils.getchildelementbytagname(element,</code><code>"argument-resolvers"</code><code>);</code>

<code>        </code><code>if</code> <code>(resolverselement !=</code><code>null</code><code>) {</code>

<code>            </code><code>managedlist&lt;beandefinitionholder&gt; argumentresolvers = extractbeansubelements(resolverselement, parsercontext);</code>

<code>            </code><code>return</code> <code>wrapwebargumentresolverbeandefs(argumentresolvers, parsercontext);</code>

<code>        </code><code>return</code> <code>null</code><code>;</code>

從上面的代碼可以看出,擷取我們自定義的handlermethodargumentresolver然後把它設定進requestmappinghandleradapter的customargumentresolvers參數中,requestmappinghandleradapter有兩個與handlermethodargumentresolver有關的參數: 

<code>private</code> <code>list&lt;handlermethodargumentresolver&gt; customargumentresolvers;</code>

<code>private</code> <code>handlermethodargumentresolvercomposite argumentresolvers;</code>

handlermethodargumentresolvercomposite 也僅僅是内部存放一個list&lt;handlermethodargumentresolver&gt;集合,同時本身又繼承handlermethodargumentresolver,是以它的實作都是靠内部的list&lt;handlermethodargumentresolver&gt;集合來實作的。 

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<code>private</code> <code>final</code> <code>list&lt;handlermethodargumentresolver&gt; argumentresolvers =</code>

<code>            </code><code>new</code> <code>linkedlist&lt;handlermethodargumentresolver&gt;();</code>

<code>//使用了适合高并發的concurrenthashmap來進行緩存</code>

<code>    </code><code>private</code> <code>final</code> <code>map&lt;methodparameter, handlermethodargumentresolver&gt; argumentresolvercache =</code>

<code>            </code><code>new</code> <code>concurrenthashmap&lt;methodparameter, handlermethodargumentresolver&gt;(</code><code>256</code><code>);</code>

<code>    </code><code>/**</code>

<code>     </code><code>* return a read-only list with the contained resolvers, or an empty list.</code>

<code>    </code><code>public</code> <code>list&lt;handlermethodargumentresolver&gt; getresolvers() {</code>

<code>        </code><code>return</code> <code>collections.unmodifiablelist(</code><code>this</code><code>.argumentresolvers);</code>

<code>     </code><code>* whether the given {@linkplain methodparameter method parameter} is supported by any registered</code>

<code>     </code><code>* {@link handlermethodargumentresolver}.</code>

<code>        </code><code>return</code> <code>getargumentresolver(parameter) !=</code><code>null</code><code>;</code>

<code>     </code><code>* iterate over registered {@link handlermethodargumentresolver}s and invoke the one that supports it.</code>

<code>     </code><code>* @exception illegalstateexception if no suitable {@link handlermethodargumentresolver} is found.</code>

<code>        </code><code>handlermethodargumentresolver resolver = getargumentresolver(parameter);</code>

<code>        </code><code>assert.notnull(resolver,</code><code>"unknown parameter type ["</code> <code>+ parameter.getparametertype().getname() +</code><code>"]"</code><code>);</code>

<code>        </code><code>return</code> <code>resolver.resolveargument(parameter, mavcontainer, webrequest, binderfactory);</code>

<code>     </code><code>* find a registered {@link handlermethodargumentresolver} that supports the given method parameter.</code>

<code>    </code><code>private</code> <code>handlermethodargumentresolver getargumentresolver(methodparameter parameter) {</code>

<code>        </code><code>handlermethodargumentresolver result =</code><code>this</code><code>.argumentresolvercache.get(parameter);</code>

<code>        </code><code>if</code> <code>(result ==</code><code>null</code><code>) {</code>

<code>            </code><code>for</code> <code>(handlermethodargumentresolver methodargumentresolver :</code><code>this</code><code>.argumentresolvers) {</code>

<code>                </code><code>if</code> <code>(logger.istraceenabled()) {</code>

<code>                    </code><code>logger.trace(</code><code>"testing if argument resolver ["</code> <code>+ methodargumentresolver +</code><code>"] supports ["</code> <code>+</code>

<code>                            </code><code>parameter.getgenericparametertype() +</code><code>"]"</code><code>);</code>

<code>                </code><code>if</code> <code>(methodargumentresolver.supportsparameter(parameter)) {</code>

<code>                    </code><code>result = methodargumentresolver;</code>

<code>                    </code><code>this</code><code>.argumentresolvercache.put(parameter, result);</code>

<code>                    </code><code>break</code><code>;</code>

<code>        </code><code>return</code> <code>result;</code>

在requestmappinghandleradapter完成參數設定後,會調用afterpropertiesset方法 

<code>    </code><code>public</code> <code>void</code> <code>afterpropertiesset() {</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.argumentresolvers ==</code><code>null</code><code>) {</code>

<code>            </code><code>list&lt;handlermethodargumentresolver&gt; resolvers = getdefaultargumentresolvers();</code>

<code>            </code><code>this</code><code>.argumentresolvers =</code><code>new</code> <code>handlermethodargumentresolvercomposite().addresolvers(resolvers);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.initbinderargumentresolvers ==</code><code>null</code><code>) {</code>

<code>            </code><code>list&lt;handlermethodargumentresolver&gt; resolvers = getdefaultinitbinderargumentresolvers();</code>

<code>            </code><code>this</code><code>.initbinderargumentresolvers =</code><code>new</code> <code>handlermethodargumentresolvercomposite().addresolvers(resolvers);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.returnvaluehandlers ==</code><code>null</code><code>) {</code>

<code>            </code><code>list&lt;handlermethodreturnvaluehandler&gt; handlers = getdefaultreturnvaluehandlers();</code>

<code>            </code><code>this</code><code>.returnvaluehandlers =</code><code>new</code> <code>handlermethodreturnvaluehandlercomposite().addhandlers(handlers);</code>

<code>        </code><code>initcontrolleradvicecache();</code>

getdefaultargumentresolvers方法完成了所有的handlermethodargumentresolver的彙總,如下: 

<code>private</code> <code>list&lt;handlermethodargumentresolver&gt; getdefaultargumentresolvers() {</code>

<code>        </code><code>list&lt;handlermethodargumentresolver&gt; resolvers =</code><code>new</code> <code>arraylist&lt;handlermethodargumentresolver&gt;();</code>

<code>        </code><code>// annotation-based argument resolution</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestparammethodargumentresolver(getbeanfactory(),</code><code>false</code><code>));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestparammapmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>pathvariablemethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>pathvariablemapmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>matrixvariablemethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>matrixvariablemapmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>servletmodelattributemethodprocessor(</code><code>false</code><code>));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestresponsebodymethodprocessor(getmessageconverters()));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestpartmethodargumentresolver(getmessageconverters()));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestheadermethodargumentresolver(getbeanfactory()));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestheadermapmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>servletcookievaluemethodargumentresolver(getbeanfactory()));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>expressionvaluemethodargumentresolver(getbeanfactory()));</code>

<code>        </code><code>// type-based argument resolution</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>servletrequestmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>servletresponsemethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>httpentitymethodprocessor(getmessageconverters()));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>redirectattributesmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>modelmethodprocessor());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>mapmethodprocessor());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>errorsmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>sessionstatusmethodargumentresolver());</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>uricomponentsbuildermethodargumentresolver());</code>

<code>        </code><code>// custom arguments</code>

<code>//擷取我們自定義的handlermethodargumentresolver</code>

<code>        </code><code>if</code> <code>(getcustomargumentresolvers() !=</code><code>null</code><code>) {</code>

<code>            </code><code>resolvers.addall(getcustomargumentresolvers());</code>

<code>        </code><code>// catch-all</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>requestparammethodargumentresolver(getbeanfactory(),</code><code>true</code><code>));</code>

<code>        </code><code>resolvers.add(</code><code>new</code> <code>servletmodelattributemethodprocessor(</code><code>true</code><code>));</code>

<code>        </code><code>return</code> <code>resolvers;</code>

不僅彙總了spring預設的,同時加進來我們自定義的handlermethodargumentresolver。至此,handlermethodargumentresolver的來龍去脈都說清楚了。然後就是我們自定義handlermethodargumentresolver,下一篇文章再說。