在dwr.xml中有,<creator>标签负责公开用于Web远程的类和类的方法,实际上最后调用的就是本包下面的script创建类。 creator类型在1.1版本的时候有如下几种,现在是3.0版本了,我查了下源码,种类好像比下面要多(查XXXCreator有多少个)。 new: 用Java的new关键字创造对象。 none: 它不创建对象,看下面的原因。 (v1.1+) scripted: 通过BSF使用脚本语言创建对象,例如BeanShell或Groovy。 spring: 通过Spring框架访问Bean。 jsf: 使用JSF的Bean。 (v1.1+) struts: 使用Struts的FormBean。 (v1.1+) pageflow: 访问Beehive或Weblogic的PageFlow。 (v1.1+) creator是在什么时候调用的呢? 实际上,在Serlvet加载的时候有个doPost方法,doPost方法调用handle,handle再调用 remotor,remotor最终调用相应的creator,比如NewCreator,creator实际上是执行创建script字符串的工作。 举例来说,我们想在html中某个地方直接显示当前时间的long值,那么我们就可以调用java.util.Date类的getTime()方法。dwr.xml中写法如下:
<
dwr
>
<
allow
>
<
createcreator
=
"
new
"
javascript
=
"
JDate
"
>
<
paramname
=
"
class
"
value
=
"
java.util.Date
"
/>
</
create
>
<
createcreator
=
"
new
"
javascript
=
"
Demo
"
>
<
paramname
=
"
class
"
value
=
"
your.java.Bean
"
/>
</
create
>
</
allow
>
</
dwr
>
我们知道这样所有的/dwr/*所有请求都由这个servlet来处理,那么实际上,浏览器加载 <script type='text/javascript' src='dwr/interface/JDate.js'></script>时,实际上是在触发servlet,这次触发属于系统 触发,不做事的,只有执行javascript调用方法时如:
function
getServerDateTime()
{ JDate.getTime(handleGetTime); }
function
handleGetTime(dateTime)
{ DWRUtil.setValue( " date " ,dateTime); }
才会触发下面
protected
void
doGet(HttpServletRequestreq,HttpServletResponseresp)
throws
IOException,ServletException
{ doPost(req,resp); }
doGet会调用到doPost
protected
void
doPost(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException,ServletException
{ try { webContextBuilder.set(request,response,getServletConfig(),getServletContext(),container); UrlProcessorprocessor = container.getBean(UrlProcessor. class ); processor.handle(request,response); } finally { webContextBuilder.unset(); } }
在proccessor中我们看到如下代码
public
void
handle(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException
{ try { StringpathInfo = request.getPathInfo(); contextPath = request.getContextPath(); if (pathInfo == null || pathInfo.length() == 0 || " / " .equals(pathInfo)) { response.sendRedirect(contextPath + request.getServletPath() + indexHandlerUrl); } else { // LoopthroughalltheknownURLs for (Entry < String,Object > entry:urlMapping.entrySet()) { Stringurl = entry.getKey(); // IfthisURLmatches,callthehandler if (pathInfo.startsWith(url)) { Handlerhandler = (Handler)entry.getValue(); handler.handle(request,response); return ; } } notFoundHandler.handle(request,response); } }catch (Exceptionex) { exceptionHandler.setException(ex); exceptionHandler.handle(request,response); } }
这些handle有多种 1, /** * A Handler that supports requests for auth.js */ public class AuthHandler extends JavaScriptHandler 2, /** * A Handler that supports requests for engine.js * @author Joe Walker [joe at getahead dot ltd dot uk] */ public class EngineHandler extends JavaScriptHandler 3, /** * A Handler that supports requests for util.js * @author Joe Walker [joe at getahead dot ltd dot uk] */ public class GiHandler extends JavaScriptHandler 4, /** * A handler for interface generation requests * @author Joe Walker [joe at getahead dot ltd dot uk] */ public class InterfaceHandler extends JavaScriptHandler 上面三种都是系统范围的handle,对于我们自己编写的类,应该是触发InterfaceHandler 。 我们再看如下关系 public abstract class CachingFileHandler implements Handler public abstract class TemplateHandler extends CachingFileHandler public abstract class JavaScriptHandler extends TemplateHandler public class InterfaceHandler extends JavaScriptHandler 逐级往上继承 InterfaceHandler,我们看到如下代码,执行顺序-4,里面调用了远程remoter
protected
StringgenerateTemplate(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException
{ StringscriptName = request.getPathInfo(); scriptName = scriptName.replace(interfaceHandlerUrl, "" ); StringcontextServletPath = request.getContextPath() + request.getServletPath(); if (scriptName.endsWith(PathConstants.EXTENSION_JS)) { scriptName = scriptName.replace(PathConstants.EXTENSION_JS, "" ); if ( ! LocalUtil.isJavaIdentifier(scriptName)) { log.debug( " Throwingatrequestforscriptwithname:' " + scriptName + " ' " ); throw new SecurityException( " ScriptnamesmayonlycontainJavaIdentifiers " ); } return remoter.generateInterfaceScript(scriptName,contextServletPath); } else if (scriptName.endsWith(PathConstants.EXTENSION_SDOC)) { scriptName = scriptName.replace(PathConstants.EXTENSION_SDOC, "" ); if ( ! LocalUtil.isJavaIdentifier(scriptName)) { log.debug( " Throwingatrequestforscriptwithname:' " + scriptName + " ' " ); throw new SecurityException( " ScriptnamesmayonlycontainJavaIdentifiers " ); } return remoter.generateInterfaceSDoc(scriptName,contextServletPath); } else { log.debug( " Throwingatrequestforscriptwithunknownextension:' " + scriptName + " ' " ); throw new SecurityException( " Unknownextension " ); } }
类JavaScriptHandler代码如下,调用了父类TemplateHandler的generateCachableContent方法执行顺序-2
protected
StringgenerateCachableContent(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException
{ Stringoutput = super .generateCachableContent(request,response); if (debug || compressor == null ) { return output; } try { return compressor.compressJavaScript(output); } catch (Exceptionex) { log.warn( " Compressionsystem( " + compressor.getClass().getSimpleName() + " )failedtocompressscript " ,ex); return output; } }
TemplateHandler类代码如下执行顺序-3,里面调用了generateTemplate方法
protected
StringgenerateCachableContent(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException
{ Stringtemplate = generateTemplate(request,response); Map < String,String > replace = getSearchReplacePairs(); if (replace != null ) { for (Map.Entry < String,String > entry:replace.entrySet()) { Stringsearch = entry.getKey(); if (template.contains(search)) { template = template.replace(search,entry.getValue()); } } }return template; }
/***/
/** *Generateatemplatetoundergosearchandreplaceprocessingaccordingto *thesearchandreplacepairsfrom{@link #getSearchReplacePairs()}. * @param requestTheHTTPrequestdata * @param responseWherewewritetheHTTPresponsedata * @return Atemplatestringcontaining${}sectionstobereplaced */
protected
abstract
StringgenerateTemplate(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException;
CachingFileHandler类代码如下,handle方法里面调用了generateCachableContent()方法 执行顺序-1
public
void
handle(HttpServletRequestrequest,HttpServletResponseresponse)
throws
IOException
{ if (isUpToDate(request)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return ; } Stringoutput;synchronized (scriptCache) { Stringurl = request.getPathInfo(); output = scriptCache.get(url); if (output == null ) { output = generateCachableContent(request,response); } scriptCache.put(url,output); } response.setContentType(mimeType); response.setDateHeader(HttpConstants.HEADER_LAST_MODIFIED,CONTAINER_START_TIME); response.setHeader(HttpConstants.HEADER_ETAG,ETAG); PrintWriterout= response.getWriter(); out.println(output); }
代码有点绕 我们看到在InterfaceHandler类中 有一行代码如下: remoter.generateInterfaceScript(scriptName, contextServletPath); 如果按例子,对于声明在dwr.xml中的JDate类,scriptName应该是JDate,contextServletPath应该是'dwr/interface/'
执行generateInterfaceScript方法生成相应的字符串,对应于JDate.js 在CachingFileHandler类中的方法handle最后一行如下, out.println(output); 在这个地方,将返回内容输出到客户端。