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<string,object> getformdata(date date){</code>
<code> </code><code>map<string,object> map=</code><code>new</code> <code>hashmap<string,object>();</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><mvc:annotation-driven /></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<?> handlertype = handlermethod.getbeantype();</code>
<code> </code><code>set<method> 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<invocablehandlermethod> initbindermethods =</code><code>new</code> <code>arraylist<invocablehandlermethod>();</code>
<code> </code><code>// global methods first</code>
<code>//关注点2:再寻找出全局的初始化binder的方法</code>
<code> </code><code>for</code> <code>(entry<controlleradvicebean, set<method>> 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<invocablehandlermethod> 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 < 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<?> 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) && (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<object>(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<multipartfile> 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>&& binder.gettarget() !=</code><code>null</code> <code>&&</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<string> 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><t> t convertifnecessary(string propertyname, object oldvalue, object newvalue,</code>
<code> </code><code>class<t> 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的具体的转换过程。至此,大体过程就算是完了。