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的具體的轉換過程。至此,大體過程就算是完了。