在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>
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
<create creator="new" javascript="Demo">
<param name="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(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException

{
doPost(req, resp);
}
doGet會調用到doPost
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException

{
try

{
webContextBuilder.set(request, response, getServletConfig(), getServletContext(), container);

UrlProcessor processor = container.getBean(UrlProcessor.class);
processor.handle(request, response);
}
finally

{
webContextBuilder.unset();
}
}
在proccessor中我們看到如下代碼
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException

{
try

{
String pathInfo = request.getPathInfo();
contextPath = request.getContextPath();

if (pathInfo == null || pathInfo.length() == 0 || "/".equals(pathInfo))

{
response.sendRedirect(contextPath + request.getServletPath() + indexHandlerUrl);
}
else

{
// Loop through all the known URLs
for (Entry<String, Object> entry : urlMapping.entrySet())

{
String url = entry.getKey();

// If this URL matches, call the handler
if (pathInfo.startsWith(url))

{
Handler handler = (Handler) entry.getValue();
handler.handle(request, response);
return;
}
}

notFoundHandler.handle(request, response);
}
}
catch (Exception ex)

{
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 String generateTemplate(HttpServletRequest request, HttpServletResponse response) throws IOException

{
String scriptName = request.getPathInfo();
scriptName = scriptName.replace(interfaceHandlerUrl, "");

String contextServletPath = request.getContextPath() + request.getServletPath();

if (scriptName.endsWith(PathConstants.EXTENSION_JS))

{
scriptName = scriptName.replace(PathConstants.EXTENSION_JS, "");
if (!LocalUtil.isJavaIdentifier(scriptName))

{
log.debug("Throwing at request for script with name: '" + scriptName + "'");
throw new SecurityException("Script names may only contain Java Identifiers");
}

return remoter.generateInterfaceScript(scriptName, contextServletPath);
}
else if (scriptName.endsWith(PathConstants.EXTENSION_SDOC))

{
scriptName = scriptName.replace(PathConstants.EXTENSION_SDOC, "");
if (!LocalUtil.isJavaIdentifier(scriptName))

{
log.debug("Throwing at request for script with name: '" + scriptName + "'");
throw new SecurityException("Script names may only contain Java Identifiers");
}

return remoter.generateInterfaceSDoc(scriptName, contextServletPath);
}
else

{
log.debug("Throwing at request for script with unknown extension: '" + scriptName + "'");
throw new SecurityException("Unknown extension");
}
}
類JavaScriptHandler代碼如下,調用了父類TemplateHandler的generateCachableContent方法
執行順序-2
protected String generateCachableContent(HttpServletRequest request, HttpServletResponse response) throws IOException

{
String output = super.generateCachableContent(request, response);

if (debug || compressor == null)

{
return output;
}

try

{
return compressor.compressJavaScript(output);
}
catch (Exception ex)

{
log.warn("Compression system (" + compressor.getClass().getSimpleName() +") failed to compress script", ex);
return output;
}
}

TemplateHandler類代碼如下
執行順序-3,里面調用了generateTemplate方法
protected String generateCachableContent(HttpServletRequest request, HttpServletResponse response) throws IOException

{
String template = generateTemplate(request, response);

Map<String, String> replace = getSearchReplacePairs();
if (replace != null)

{
for (Map.Entry<String, String> entry : replace.entrySet())

{
String search = entry.getKey();
if (template.contains(search))

{
template = template.replace(search, entry.getValue());
}
}
}

return template;
}


/** *//**
* Generate a template to undergo search and replace processing according to
* the search and replace pairs from {@link #getSearchReplacePairs()}.
* @param request The HTTP request data
* @param response Where we write the HTTP response data
* @return A template string containing ${} sections to be replaced
*/
protected abstract String generateTemplate(HttpServletRequest request, HttpServletResponse response) throws IOException;

CachingFileHandler類代碼如下,handle方法里面調用了generateCachableContent()方法
執行順序-1
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException

{
if (isUpToDate(request))

{
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}

String output;

synchronized (scriptCache)

{
String url = 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);

PrintWriter out = 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);
在這個地方,將返回內容輸出到客戶端。