天天看點

SpringMVC源碼總結(八)類型轉換PropertyEditor的背後

propertyeditor是spring最初采用的轉換政策。将會轉移到converter上。本文章主要對@initbinder注解背後代碼層面的運作過程做介紹。是以最好先熟悉它的用法然後來看通代碼流程。 

先看執行個體,controller代碼如下: 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<code>@controller</code>

<code>public</code> <code>class</code> <code>formaction{</code>

<code>    </code> 

<code>// 這樣的方法裡,一般是用來注冊一些propertyeditor</code>

<code>    </code><code>@initbinder</code> 

<code>    </code><code>public</code> <code>void</code> <code>initbinder(webdatabinder binder)</code><code>throws</code> <code>exception { </code>

<code>        </code><code>dateformat df =</code><code>new</code> <code>simpledateformat(</code><code>"yyyy---mm---dd hh:mm:ss"</code><code>); </code>

<code>        </code><code>customdateeditor dateeditor =</code><code>new</code> <code>customdateeditor(df,</code><code>true</code><code>); </code>

<code>        </code><code>binder.registercustomeditor(date.</code><code>class</code><code>, dateeditor);     </code>

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

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

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

<code>    </code><code>public</code> <code>map&lt;string,object&gt; getformdata(date date){</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>

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

<code>}</code>

xml檔案僅僅開啟mvc:ananotation-driven: 

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

然後通路  http://localhost:8080/test/json?date=2014---08---3 03:34:23,便看到成功的擷取到了資料。接下來源代碼代碼分析這一過程: 

由于使用了@requestmapping是以會選擇requestmappinghandleradapter來排程執行相應的方法,如下: 

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

<code>/**</code>

<code>     </code><code>* invoke the {@link requestmapping} handler method preparing a {@link modelandview}</code>

<code>     </code><code>* if view resolution is required.</code>

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

<code>    </code><code>private</code> <code>modelandview invokehandlemethod(httpservletrequest request,</code>

<code>            </code><code>httpservletresponse response, handlermethod handlermethod)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>servletwebrequest webrequest =</code><code>new</code> <code>servletwebrequest(request, response);</code>

<code>//我們關注的重點重點重點重點重點重點重點重點</code>

<code>        </code><code>webdatabinderfactory binderfactory = getdatabinderfactory(handlermethod);</code>

<code>        </code><code>modelfactory modelfactory = getmodelfactory(handlermethod, binderfactory);</code>

<code>        </code><code>servletinvocablehandlermethod requestmappingmethod = createrequestmappingmethod(handlermethod, binderfactory);</code>

<code>        </code><code>modelandviewcontainer mavcontainer =</code><code>new</code> <code>modelandviewcontainer();</code>

<code>        </code><code>mavcontainer.addallattributes(requestcontextutils.getinputflashmap(request));</code>

<code>        </code><code>modelfactory.initmodel(webrequest, mavcontainer, requestmappingmethod);</code>

<code>        </code><code>mavcontainer.setignoredefaultmodelonredirect(</code><code>this</code><code>.ignoredefaultmodelonredirect);</code>

<code>        </code><code>asyncwebrequest asyncwebrequest = webasyncutils.createasyncwebrequest(request, response);</code>

<code>        </code><code>asyncwebrequest.settimeout(</code><code>this</code><code>.asyncrequesttimeout);</code>

<code>        </code><code>final</code> <code>webasyncmanager asyncmanager = webasyncutils.getasyncmanager(request);</code>

<code>        </code><code>asyncmanager.settaskexecutor(</code><code>this</code><code>.taskexecutor);</code>

<code>        </code><code>asyncmanager.setasyncwebrequest(asyncwebrequest);</code>

<code>        </code><code>asyncmanager.registercallableinterceptors(</code><code>this</code><code>.callableinterceptors);</code>

<code>        </code><code>asyncmanager.registerdeferredresultinterceptors(</code><code>this</code><code>.deferredresultinterceptors);</code>

<code>        </code><code>if</code> <code>(asyncmanager.hasconcurrentresult()) {</code>

<code>            </code><code>object result = asyncmanager.getconcurrentresult();</code>

<code>            </code><code>mavcontainer = (modelandviewcontainer) asyncmanager.getconcurrentresultcontext()[</code><code>0</code><code>];</code>

<code>            </code><code>asyncmanager.clearconcurrentresult();</code>

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

<code>                </code><code>logger.debug(</code><code>"found concurrent result value ["</code> <code>+ result +</code><code>"]"</code><code>);</code>

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

<code>            </code><code>requestmappingmethod = requestmappingmethod.wrapconcurrentresult(result);</code>

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

<code>        </code><code>requestmappingmethod.invokeandhandle(webrequest, mavcontainer);</code>

<code>        </code><code>if</code> <code>(asyncmanager.isconcurrenthandlingstarted()) {</code>

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

<code>        </code><code>return</code> <code>getmodelandview(mavcontainer, modelfactory, webrequest);</code>

這裡面就是整個執行過程。首先綁定請求參數到方法的參數上,然後執行方法,接下來根據方法傳回的類型來選擇合适的handlermethodreturnvaluehandler來進行處理,最後要麼走view路線,要麼直接寫入response的body中傳回。 

我們此時關注的重點是:如何綁定請求參數到方法的參數上的呢? 

webdatabinderfactory binderfactory = getdatabinderfactory(handlermethod); 

針對每次對該handlermethod請求産生一個綁定工廠,由這個工廠來完成資料的綁定。 

這裡的handlermethod包含了 controller對象formaction和、test/json映射到的方法即getformdata。 

然後詳細看下getdatabinderfactory的實作: 

<code>private</code> <code>webdatabinderfactory getdatabinderfactory(handlermethod handlermethod)</code><code>throws</code> <code>exception {</code>

<code>//這裡的handlertype便是controller的類型formaction</code>

<code>        </code><code>class&lt;?&gt; handlertype = handlermethod.getbeantype();</code>

<code>        </code><code>set&lt;method&gt; methods =</code><code>this</code><code>.initbindercache.get(handlertype);</code>

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

<code>//關注點1:找出formaction類的所有的含有@initbinder的方法(方法的傳回類型必須為void),找到後同時緩存起來</code>

<code>            </code><code>methods = handlermethodselector.selectmethods(handlertype, init_binder_methods);</code>

<code>            </code><code>this</code><code>.initbindercache.put(handlertype, methods);</code>

<code>        </code><code>list&lt;invocablehandlermethod&gt; initbindermethods =</code><code>new</code> <code>arraylist&lt;invocablehandlermethod&gt;();</code>

<code>        </code><code>// global methods first</code>

<code>//關注點2:再尋找出全局的初始化binder的方法</code>

<code>        </code><code>for</code> <code>(entry&lt;controlleradvicebean, set&lt;method&gt;&gt; entry :</code><code>this</code><code>.initbinderadvicecache .entryset()) {</code>

<code>            </code><code>if</code> <code>(entry.getkey().isapplicabletobeantype(handlertype)) {</code>

<code>                </code><code>object bean = entry.getkey().resolvebean();</code>

<code>                </code><code>for</code> <code>(method method : entry.getvalue()) {</code>

<code>                    </code><code>initbindermethods.add(createinitbindermethod(bean, method));</code>

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

<code>        </code><code>for</code> <code>(method method : methods) {</code>

<code>            </code><code>object bean = handlermethod.getbean();</code>

<code>            </code><code>initbindermethods.add(createinitbindermethod(bean, method));</code>

<code>//關注點3:找到了所有的與該handlermethod有關的初始化binder的方法,儲存起來</code>

<code>        </code><code>return</code> <code>createdatabinderfactory(initbindermethods);</code>

上面稍微做了些注釋,然後看下詳細的内容: 

關注點1:就是使用過濾,過濾類為:init_binder_methods,如下 

<code>     </code><code>* methodfilter that matches {@link initbinder @initbinder} methods.</code>

<code>    </code><code>public</code> <code>static</code> <code>final</code> <code>methodfilter init_binder_methods =</code><code>new</code> <code>methodfilter() {</code>

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

<code>        </code><code>public</code> <code>boolean</code> <code>matches(method method) {</code>

<code>            </code><code>return</code> <code>annotationutils.findannotation(method, initbinder.</code><code>class</code><code>) !=</code><code>null</code><code>;</code>

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

這個過濾類就是在handlertype即formaction中過濾那些含有@initbinder注解的方法。找到了之後就緩存起來,供下次使用。key為:handlertype,value為找到的方法。存至initbindercache中。 

關注點2:從initbinderadvicecache中擷取所有支援這個handlertype的method。這一塊有待繼續研究,這個initbinderadvicecache是如何初始化來的等等。針對目前的工程來說,initbinderadvicecache是為空的。 

關注點3:周遊所有找到的和handlertype有關的method,然後封裝成invocablehandlermethod,如下: 

<code>for</code> <code>(method method : methods) {</code>

<code>private</code> <code>invocablehandlermethod createinitbindermethod(object bean, method method) {</code>

<code>        </code><code>invocablehandlermethod bindermethod =</code><code>new</code> <code>invocablehandlermethod(bean, method);</code>

<code>        </code><code>bindermethod.sethandlermethodargumentresolvers(</code><code>this</code><code>.initbinderargumentresolvers);</code>

<code>        </code><code>bindermethod.setdatabinderfactory(</code><code>new</code> <code>defaultdatabinderfactory(</code><code>this</code><code>.webbindinginitializer));</code>

<code>        </code><code>bindermethod.setparameternamediscoverer(</code><code>this</code><code>.parameternamediscoverer);</code>

<code>        </code><code>return</code> <code>bindermethod;</code>

在封裝的過程中,同時設定一些requestmappinghandleradapter的一些參數進去initbinderargumentresolvers、webbindinginitializer、parameternamediscoverer。 

封裝完所有的方法後,建立出最終的webdatabinderfactory。如下: 

<code>protected</code> <code>initbinderdatabinderfactory createdatabinderfactory(list&lt;invocablehandlermethod&gt; bindermethods)</code>

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

<code>        </code><code>return</code> <code>new</code> <code>servletrequestdatabinderfactory(bindermethods, getwebbindinginitializer());</code>

getwebbindinginitializer()也是requestmappinghandleradapter的webbindinginitializer參數。 

至此綁定資料的工廠完成了,包含了這個handlertype的所有的propertyeditor。這是準備工作,然後就是等待執行這個我們自己的方法getformdata執行時來完成參數的綁定過程。 

綁定參數過程即getformdata的執行過程如下: 

<code>servletinvocablehandlermethod requestmappingmethod = createrequestmappingmethod(handlermethod, binderfactory);</code>

<code>略</code>

<code>requestmappingmethod.invokeandhandle(webrequest, mavcontainer);</code>

其中的requestmappingmethod經過了進一步的包裝,已經包含剛才已經建立的綁定工廠。 

執行過程如下: 

<code>public</code> <code>final</code> <code>object invokeforrequest(nativewebrequest request, modelandviewcontainer mavcontainer,</code>

<code>            </code><code>object... providedargs)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>object[] args = getmethodargumentvalues(request, mavcontainer, providedargs);</code>

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

<code>            </code><code>stringbuilder sb =</code><code>new</code> <code>stringbuilder(</code><code>"invoking ["</code><code>);</code>

<code>            </code><code>sb.append(getbeantype().getsimplename()).append(</code><code>"."</code><code>);</code>

<code>            </code><code>sb.append(getmethod().getname()).append(</code><code>"] method with arguments "</code><code>);</code>

<code>            </code><code>sb.append(arrays.aslist(args));</code>

<code>            </code><code>logger.trace(sb.tostring());</code>

<code>        </code><code>object returnvalue = invoke(args);</code>

<code>            </code><code>logger.trace(</code><code>"method ["</code> <code>+ getmethod().getname() +</code><code>"] returned ["</code> <code>+ returnvalue +</code><code>"]"</code><code>);</code>

<code>        </code><code>return</code> <code>returnvalue;</code>

分兩大步,綁定參數和執行方法體。最重要的就是如何來綁定參數呢? 

<code>private</code> <code>object[] getmethodargumentvalues(nativewebrequest request, modelandviewcontainer mavcontainer,</code>

<code>        </code><code>methodparameter[] parameters = getmethodparameters();</code>

<code>        </code><code>object[] args =</code><code>new</code> <code>object[parameters.length];</code>

<code>        </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i &lt; parameters.length; i++) {</code>

<code>            </code><code>methodparameter parameter = parameters[i];</code>

<code>            </code><code>parameter.initparameternamediscovery(</code><code>this</code><code>.parameternamediscoverer);</code>

<code>            </code><code>generictyperesolver.resolveparametertype(parameter, getbean().getclass());</code>

<code>            </code><code>args[i] = resolveprovidedargument(parameter, providedargs);</code>

<code>            </code><code>if</code> <code>(args[i] !=</code><code>null</code><code>) {</code>

<code>                </code><code>continue</code><code>;</code>

<code>            </code><code>if</code> <code>(</code><code>this</code><code>.argumentresolvers.supportsparameter(parameter)) {</code>

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

<code>                    </code><code>args[i] =</code><code>this</code><code>.argumentresolvers.resolveargument(</code>

<code>                            </code><code>parameter, mavcontainer, request,</code><code>this</code><code>.databinderfactory);</code>

<code>                    </code><code>continue</code><code>;</code>

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

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

<code>                        </code><code>logger.trace(getargumentresolutionerrormessage(</code><code>"error resolving argument"</code><code>, i), ex);</code>

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

<code>                    </code><code>throw</code> <code>ex;</code>

<code>            </code><code>if</code> <code>(args[i] ==</code><code>null</code><code>) {</code>

<code>                </code><code>string msg = getargumentresolutionerrormessage(</code><code>"no suitable resolver for argument"</code><code>, i);</code>

<code>                </code><code>throw</code> <code>new</code> <code>illegalstateexception(msg);</code>

<code>        </code><code>return</code> <code>args;</code>

綁定參數又引出來另一個重要名詞:handlermethodargumentresolver。args[i] = this.argumentresolvers.resolveargument( 

parameter, mavcontainer, request, this.databinderfactory);的具體内容如下: 

<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>@override</code>

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

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

<code>            </code><code>nativewebrequest webrequest, webdatabinderfactory binderfactory)</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>

周遊所有已注冊的handlermethodargumentresolver,然後找出一個适合的來進行參數綁定,對于本工程來說,getformdata(date date)的參數date預設是request params級别的,是以使用requestparammethodargumentresolver來處理這一過程。處理過程如下: 

<code>@override</code>

<code>    </code><code>public</code> <code>final</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>class&lt;?&gt; paramtype = parameter.getparametertype();</code>

<code>        </code><code>namedvalueinfo namedvalueinfo = getnamedvalueinfo(parameter);</code>

<code>        </code><code>object arg = resolvename(namedvalueinfo.name, parameter, webrequest);</code>

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

<code>            </code><code>if</code> <code>(namedvalueinfo.defaultvalue !=</code><code>null</code><code>) {</code>

<code>                </code><code>arg = resolvedefaultvalue(namedvalueinfo.defaultvalue);</code>

<code>            </code><code>else</code> <code>if</code> <code>(namedvalueinfo.required) {</code>

<code>                </code><code>handlemissingvalue(namedvalueinfo.name, parameter);</code>

<code>            </code><code>arg = handlenullvalue(namedvalueinfo.name, arg, paramtype);</code>

<code>        </code><code>else</code> <code>if</code> <code>(</code><code>""</code><code>.equals(arg) &amp;&amp; (namedvalueinfo.defaultvalue !=</code><code>null</code><code>)) {</code>

<code>            </code><code>arg = resolvedefaultvalue(namedvalueinfo.defaultvalue);</code>

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

<code>            </code><code>webdatabinder binder = binderfactory.createbinder(webrequest,</code><code>null</code><code>, namedvalueinfo.name);</code>

<code>            </code><code>arg = binder.convertifnecessary(arg, paramtype, parameter);</code>

<code>        </code><code>handleresolvedvalue(arg, namedvalueinfo.name, parameter, mavcontainer, webrequest);</code>

<code>        </code><code>return</code> <code>arg;</code>

namedvalueinfo namedvalueinfo = getnamedvalueinfo(parameter);擷取參數資訊,就是按照@requestparam的3個屬性來收集的,即defaultvalue=null、required=false、name=date, 

object arg = resolvename(namedvalueinfo.name, parameter, webrequest);然後就是擷取原始資料,擷取過程如下: 

47

48

49

50

51

52

53

54

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

<code>        </code><code>object arg;</code>

<code>        </code><code>httpservletrequest servletrequest = webrequest.getnativerequest(httpservletrequest.</code><code>class</code><code>);</code>

<code>        </code><code>multiparthttpservletrequest multipartrequest =</code>

<code>            </code><code>webutils.getnativerequest(servletrequest, multiparthttpservletrequest.</code><code>class</code><code>);</code>

<code>        </code><code>if</code> <code>(multipartfile.</code><code>class</code><code>.equals(parameter.getparametertype())) {</code>

<code>            </code><code>assertismultipartrequest(servletrequest);</code>

<code>            </code><code>assert.notnull(multipartrequest,</code><code>"expected multiparthttpservletrequest: is a multipartresolver configured?"</code><code>);</code>

<code>            </code><code>arg = multipartrequest.getfile(name);</code>

<code>        </code><code>else</code> <code>if</code> <code>(ismultipartfilecollection(parameter)) {</code>

<code>            </code><code>arg = multipartrequest.getfiles(name);</code>

<code>        </code><code>else</code> <code>if</code><code>(ismultipartfilearray(parameter)) {</code>

<code>            </code><code>arg = multipartrequest.getfiles(name).toarray(</code><code>new</code> <code>multipartfile[</code><code>0</code><code>]);</code>

<code>        </code><code>else</code> <code>if</code> <code>(</code><code>"javax.servlet.http.part"</code><code>.equals(parameter.getparametertype().getname())) {</code>

<code>            </code><code>arg = servletrequest.getpart(name);</code>

<code>        </code><code>else</code> <code>if</code> <code>(ispartcollection(parameter)) {</code>

<code>            </code><code>arg =</code><code>new</code> <code>arraylist&lt;object&gt;(servletrequest.getparts());</code>

<code>        </code><code>else</code> <code>if</code> <code>(ispartarray(parameter)) {</code>

<code>            </code><code>arg = requestpartresolver.resolvepart(servletrequest);</code>

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

<code>            </code><code>arg =</code><code>null</code><code>;</code>

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

<code>                </code><code>list&lt;multipartfile&gt; files = multipartrequest.getfiles(name);</code>

<code>                </code><code>if</code> <code>(!files.isempty()) {</code>

<code>                    </code><code>arg = (files.size() ==</code><code>1</code> <code>? files.get(</code><code>0</code><code>) : files);</code>

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

<code>//對于本工程,我們的重點在這裡這裡這裡這裡這裡這裡</code>

<code>                </code><code>string[] paramvalues = webrequest.getparametervalues(name);</code>

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

<code>                    </code><code>arg = paramvalues.length ==</code><code>1</code> <code>? paramvalues[</code><code>0</code><code>] : paramvalues;</code>

通過webrequest.getparametervalues(name)來擷取原始的字元串。這裡便有涉及到了容器如tomcat的處理過程,這一擷取參數的過程在本系列的第五篇文章tomcat的擷取參數中進行了詳細的源碼介紹,那一篇主要是介紹亂碼的。本文章不再介紹,接着說,這樣就可以擷取到我們請求的原始字元串"2014---08---3 03:34:23",接下來便是執行轉換綁定的過程: 

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

這一過程就是要尋找我們已經注冊的所有的propertyeditor來進行轉換,如果還沒有找到,則使用另一套轉換流程,使用conversionservice來進行轉換。我們慢慢來看這一過程,有了binderfactory便可以建立出webdatabinder,具體的建立過程如下: 

<code>public</code> <code>final</code> <code>webdatabinder createbinder(nativewebrequest webrequest, object target, string objectname)</code>

<code>        </code><code>webdatabinder databinder = createbinderinstance(target, objectname, webrequest);</code>

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

<code>            </code><code>this</code><code>.initializer.initbinder(databinder, webrequest);</code>

<code>        </code><code>initbinder(databinder, webrequest);</code>

<code>        </code><code>return</code> <code>databinder;</code>

先建立出webdatabinder,然後使用initializer的initbinder方法來初始化一些propertyeditor,initializer的類型為我們常見的configurablewebbindinginitializer即在mvc:annotation-driven時預設注冊的最終設定為requestmappinghandleradapter的webbindinginitializer屬性值。this.initializer.initbinder(databinder, webrequest);過程如下: 

<code>    </code><code>public</code> <code>void</code> <code>initbinder(webdatabinder binder, webrequest request) {</code>

<code>        </code><code>binder.setautogrownestedpaths(</code><code>this</code><code>.autogrownestedpaths);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.directfieldaccess) {</code>

<code>            </code><code>binder.initdirectfieldaccess();</code>

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

<code>            </code><code>binder.setmessagecodesresolver(</code><code>this</code><code>.messagecodesresolver);</code>

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

<code>            </code><code>binder.setbindingerrorprocessor(</code><code>this</code><code>.bindingerrorprocessor);</code>

<code>        </code><code>if</code> <code>(</code><code>this</code><code>.validator !=</code><code>null</code> <code>&amp;&amp; binder.gettarget() !=</code><code>null</code> <code>&amp;&amp;</code>

<code>                </code><code>this</code><code>.validator.supports(binder.gettarget().getclass())) {</code>

<code>            </code><code>binder.setvalidator(</code><code>this</code><code>.validator);</code>

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

<code>            </code><code>binder.setconversionservice(</code><code>this</code><code>.conversionservice);</code>

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

<code>            </code><code>for</code> <code>(propertyeditorregistrar propertyeditorregistrar :</code><code>this</code><code>.propertyeditorregistrars) {</code>

<code>                </code><code>propertyeditorregistrar.registercustomeditors(binder);</code>

即設定一些我們conversionservice、messagecodesresolver、validator 等,這些參數即我們在mvc:annotation中進行設定的,若無設定,采用預設的。 

繼續執行initbinder(databinder, webrequest); 

<code>public</code> <code>void</code> <code>initbinder(webdatabinder binder, nativewebrequest request)</code><code>throws</code> <code>exception {</code>

<code>        </code><code>for</code> <code>(invocablehandlermethod bindermethod :</code><code>this</code><code>.bindermethods) {</code>

<code>            </code><code>if</code> <code>(isbindermethodapplicable(bindermethod, binder)) {</code>

<code>                </code><code>object returnvalue = bindermethod.invokeforrequest(request,</code><code>null</code><code>, binder);</code>

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

<code>                    </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"@initbinder methods should return void: "</code> <code>+ bindermethod);</code>

執行那些适合我們已經建立的webdatabinder,怎樣才叫适合的呢?看isbindermethodapplicable(bindermethod, binder)方法 

<code>protected</code> <code>boolean</code> <code>isbindermethodapplicable(handlermethod initbindermethod, webdatabinder binder) {</code>

<code>        </code><code>initbinder annot = initbindermethod.getmethodannotation(initbinder.</code><code>class</code><code>);</code>

<code>        </code><code>collection&lt;string&gt; names = arrays.aslist(annot.value());</code>

<code>        </code><code>return</code> <code>(names.size() ==</code><code>0</code> <code>|| names.contains(binder.getobjectname()));</code>

當initbindermethod上的@initbinder注解指定了value,該value可以是多個,當它包含了我們的方法的參數date,則這個initbindermethod就會被執行。當@initbinder注解沒有指定value,則也會被執行。是以為了不用執行一些不必要的initbindermethod,我們最好為這些initbindermethod上的@initbinder加上value限定。對于我們寫的initbinder便是以開始執行了。 

由binderfactory建立出來的webdatabinder就此完成,然後才是詳細的轉換過程: 

<code>public</code> <code>&lt;t&gt; t convertifnecessary(string propertyname, object oldvalue, object newvalue,</code>

<code>            </code><code>class&lt;t&gt; requiredtype, typedescriptor typedescriptor)</code><code>throws</code> <code>illegalargumentexception {</code>

<code>        </code><code>object convertedvalue = newvalue;</code>

<code>        </code><code>// custom editor for this type?</code>

<code>        </code><code>propertyeditor editor =</code><code>this</code><code>.propertyeditorregistry.findcustomeditor(requiredtype, propertyname);</code>

<code>        </code><code>conversionfailedexception firstattemptex =</code><code>null</code><code>;</code>

<code>        </code><code>// no custom editor but custom conversionservice specified?</code>

<code>        </code><code>conversionservice conversionservice =</code><code>this</code><code>.propertyeditorregistry.getconversionservice();</code>

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

這裡首先使用已注冊的propertyeditor,當仍然沒有找到時才使用conversionservice。對于本工程來說,由于已經手動注冊了對于date的轉換的propertyeditor即customdateeditor,然後便會執行customdateeditor的具體的轉換過程。至此,大體過程就算是完了。