天天看点

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的具体的转换过程。至此,大体过程就算是完了。