`

DWR整体流程分析(二)(转)

    博客分类:
  • dwr
 
阅读更多

看一下sessionCookieName:

 

/** The session cookie name */  
dwr.engine._sessionCookieName = "${sessionCookieName}"; // JSESSION

 

 ID 

The session cookie name它也是服务器端返回给客户端的,所以说服务器端采用什么方式获得了这个sessionCookieName的形式之后,我们的dwr.engine._getJSessionId才能根据它的内容它的形式来返回我们想要的cookie,这个实现方式就是dwr所依赖的实现方式。如果dwr实现了这个cookieName是别的名字,那我们也需要dwr给返回别的名字。dwr.engine._sessionCookieName 这个名字是因框架而定。所以它会采用这样一种写法。 
我们看看打印 

 

function show(){   
alert("sessionCookieName:" + dwr.engine._sessionCookieName);   
}  

 

 打印出sessionCookieName:JSESSIONID 

那么我们现在取得的JSESSIONID就是JSESSIONID=我们所要的字符串,我们验证一下,用下面的代码:

 

var cookies = document.cookie.split(';');   
alert(cookies );  

 

 打印出JSESSIONID=FCB69D86F4E1AC9CF3900A6816。它和origScriptSessionId是不一样的。我们来看看httpSessionId(JSESSIONID),它应该是对一个客户的所有请求来讲的。会话,对多个请求只要是同一个客户都可以,因此对于同一个客户它的httpSessionId是不会变的。我们来看对同一个客户第一次请求JSESSIONID=FCB69D86F4E1AC9CF3900A6816,刷新后第二次请求JSESSIONID=FCB69D86F4E1AC9CF3900A6816,它们俩次显示的JSESSIONID是相同的。因为它们都是相当于同一会话来讲的。这个内容也就是存储在客户端,客户端发送数据的时候也要把它们发送出去,发送出去到服务器端后,服务器端判断这个SESSIONID存不存在。如果存在的话,就会根据它去取出我们所要的session,然后把当前客户这些状态取出来显示出来。 

我们看一下原始的脚本ScriptSessionId,我们知道它的产生是服务器每一次进行加载页面,页面中包含了engine.js这个资源的时候,我们会把原始的ScriptSessionId赋值,所以我们每一次的请求都会产生一个不同的ScriptSessionId。所以脚本的原始的ScriptSessionId,针对每一次的不同请求,它都会产生不同的原始的ScriptSessionId。 
(四)execute方法 
下面我们看一下脚本文件的生成: 
Demo.js: 

 

//Provide a default path to dwr.engine   
if(dwr == null) var dwr = {};   
if(dwr.engine == null) dwr.engine = {};   
if(DWREngine == null) var DWREngine = dwr.engine;   
  
if(Demo == null) var Demo = {};   
Demo._path = '/Demo1/dwr';   
Demo.sayHello = function(p0,callback){   
    dwr.engine._execute(Demo._path,'Demo','sayHello',p0,callback);   
}  

 

 这是服务器端为我们产生的脚本文件,正因为有了这个脚本文件,客户端才可以通过Demo.sayHello来访问到服务器组件。到底是怎么访问的?大家知道,dwr是基于ajax产生的,所以它必然会用到ajax的xmlHttpRequest对象,被dwr封装了,包括servlet在ajax中也需要我们来写,但是在dwr中也封装来了,只要在web.xml配置org.directwebremoting.servlet.DwrServlet就可以完成我们的处理了。这也是dwr优于ajax的一点,框架的集成度是比较高的。 

看一下Demo.sayHello,它是通过dwr.xml这个部署配置文件来动态产生的, dwr.engine._execute(Demo._path,'Demo','sayHello',p0,callback);这些东西是服务器发我们的,这是dwr的一个内部实现机制。看一下调用Demo.sayHello方法的时候,具体的操作是什么?它首先去调用函数function(p0,callback),说白了,客户端直接调用web服务器的组件呢,实际说到最终的实质也就是服务器端为我们产生一个js脚本文件,产生的这个文件是根据我们的dwr.xml部署描述文件动态生成的,生成之后呢,我们客户端就调用生成的这个文件当中的信息,然后通过这个信息再去调用engine.js文件当中的execute方法,然后把必要的参数传递进去之后,在dwr.engine._execute(Demo._path,'Demo','sayHello',p0,callback);里面完成对象的创建,包括最后的发送,最后的相应等等。所以这个引擎的脚本文件是很重要的。下面分析一下引擎脚本文件中的 
dwr.engine._execute方法: 

 

dwr.engine._execute = function(path, scriptName, methodName, vararg_params) 

 

 引擎文件的执行方法,需要4个参数,注意一点,看源码的时候, javascript定义一个函数的时候,后面的参数并不是我们在dwr.engine._execute(Demo._path,'Demo','sayHello',p0,callback);里面指定的,因为这是5个参数,但前面引擎文件的执行方法定义时却只有4个参数。这个和强类型语言有所区别,强类型语言对于函数重载方面,它参数不同,它会去调用不同的方法。但是这里如果仅仅有一个函数的话,这个函数的参数不同,它也会去调用。所以不能从参数的数量上来确定调用哪一个函数。vararg_params相当于是一个数组,相当于有很多的参数在里面,这一点一定要注意。所以客户端在调用了Demo.sayHello方法之后,会执行引擎脚本的execute方法,然后会传递几个参数Demo._path,'Demo','sayHello',p0,callback。Demo._path是在服务器端动态的生成的,它也就是指定我们请求的路径是什么。请求都是通过servlet来处理的,请求路径应该就是servlet所需要的路径。Demo指的是dwr.xml文件当中,为我们指定的javascript的属性所指定的在客户端调用的对象的方法的对象的名称,sayHello就是指定我所调用的是哪一个方法,p0就是指定调用的参数是什么(就是本例的name),callback就是回调方法。这就是我们在客户端在书写格式上要采用Demo.sayHello(text,callBack),前面text指的是参数,后面指定的是回调函数callBack。这也是和实现机制有关的,否则我们这么写为什么会去调用它,我们不得而知,但是当你看到了这个生成的引擎文件的时候,我就知道,实际我调用sayHello方法之后,传递的两个参数function(p0,callback),p0是我们传递的参数,callback是回调方法,然后吧这些信息是通过引擎文件的execute方法去执行的。但是传递这个方法的时候,会传递另外一些附加的信息。而且回调函数传过去,传过去之后在引擎中,会对数据进行分析,分析之后回传的时候会去调用callback,然后就会调用我们在index.jsp里面写的callBack(data)方法显示出数据。这就是整体流程。 

下面分析引擎文件的执行方法,看源码: 

 

dwr.engine._execute = function(path, scriptName, methodName, vararg_params){   
var singleShot = false;   
  if (dwr.engine._batch == null) {   
    dwr.engine.beginBatch();   
    singleShot = true;   
  }   
  var batch = dwr.engine._batch;   
  // To make them easy to manipulate we copy the arguments into an args array   
  var args = [];   
  for (var i = 0; i < arguments.length - 3; i++) {   
    args[i] = arguments[i + 3];   
  }   
  // All the paths MUST be to the same servlet   
  if (batch.path == null) {   
    batch.path = path;   
  }   
  else {   
    if (batch.path != path) {   
      dwr.engine._handleError(batch, { name:"dwr.engine.multipleServlets", message:"Can't batch requests to multiple DWR Servlets." });   
      return;   
    }   
  }   
  // From the other params, work out which is the function (or object with   
  // call meta-data) and which is the call parameters   
  var callData;   
  var lastArg = args[args.length - 1];   
  if (typeof lastArg == "function" || lastArg == null) callData = { callback:args.pop() };   
  else callData = args.pop();   
  
  // Merge from the callData into the batch   
  dwr.engine._mergeBatch(batch, callData);   
  batch.handlers[batch.map.callCount] = {   
    exceptionHandler:callData.exceptionHandler,   
    callback:callData.callback   
  };   
  
  // Copy to the map the things that need serializing   
  var prefix = "c" + batch.map.callCount + "-";   
  batch.map[prefix + "scriptName"] = scriptName;   
  batch.map[prefix + "methodName"] = methodName;   
  batch.map[prefix + "id"] = batch.map.callCount;   
  for (i = 0; i < args.length; i++) {   
    dwr.engine._serializeAll(batch, [], args[i], prefix + "param" + i);   
  }   
  
  // Now we have finished remembering the call, we incr the call count   
  batch.map.callCount++;   
  if (singleShot) dwr.engine.endBatch();   
  
};  

 

 path是请求的路径,scriptName是客户端所用的java对象的名称methodName是调用的方法名 vararg_params是方法的参数,这里面的参数是包括了客户端发送给服务器端需要的java方法的参数名称,还有一个就是回调函数。 

首先看看dwr.engine.beginBatch();开始一个批处理,目的是因为dwr框架在开发的时候遵循的一种方式就是说,如果多次调用java的web组件的话,我需要放在一个批处理当中来处理,这样会提高效率,避免了客户端和服务器端频繁的发生交互。所以需要一个批处理。但是默认情况下,都会采用批处理,它会生成一个Batch的批处理对象。看一下dwr.engine.beginBatch源码: 

 

dwr.engine.beginBatch = function() {   
  if (dwr.engine._batch) {   
    dwr.engine._handleError(null, { name:"dwr.engine.batchBegun", message:"Batch already begun" });   
    return;   
  }   
  dwr.engine._batch = dwr.engine._createBatch();   
}; 

 

 它也是一个函数,目的就是为了生成一个Batch批处理的对象。生成这个Bactch对象的目的是什么?也就是完成我所需要的操作,操作中的数据都是放在Bactch对象里的,然后通过Bactch来操作,beginBatch需要做的是什么呢?就是如果这个Bactch对象存在的话,就会抛出错误已经存在了,不需要创建,然后直接返回。dwr.engine._batch = 

dwr.engine._createBatch();Batch的创建是通过createBatch()来创建的,createBatch()也是一个函数,看看它的源码:

/** @private Generate a new standard batch */  
dwr.engine._createBatch = function() {   
  var batch = {   
    map:{   
      callCount:0,   
      page:window.location.pathname + window.location.search,   
      httpSessionId:dwr.engine._getJSessionId(),   
      scriptSessionId:dwr.engine._getScriptSessionId()   
    },   
    charsProcessed:0, paramCount:0,   
    parameters:{}, headers:{},   
    isPoll:false, handlers:{}, preHooks:[], postHooks:[],   
    rpcType:dwr.engine._rpcType,   
    httpMethod:dwr.engine._httpMethod,   
    async:dwr.engine._async,   
    timeout:dwr.engine._timeout,   
    errorHandler:dwr.engine._errorHandler,   
    warningHandler:dwr.engine._warningHandler,   
    textHtmlHandler:dwr.engine._textHtmlHandler   
  };   
  if(batch.xml==null)   
  {   
    batch.xml="aaa";   
    }   
  if (dwr.engine._preHook) batch.preHooks.push(dwr.engine._preHook);   
  if (dwr.engine._postHook) batch.postHooks.push(dwr.engine._postHook);   
  var propname, data;   
  if (dwr.engine._headers) {   
    for (propname in dwr.engine._headers) {   
      data = dwr.engine._headers[propname];   
      if (typeof data != "function") batch.headers[propname] = data;   
    }   
  }   
  if (dwr.engine._parameters) {   
    for (propname in dwr.engine._parameters) {   
      data = dwr.engine._parameters[propname];   
      if (typeof data != "function") batch.parameters[propname] = data;   
    }   
  }   
  return batch;   
};  

 里面有很多信息,重要的就是Batch这个变量,里面定义了很多内容。如果对javascript不是很了解,就会感到很茫然,为什么这么说呢?请看下面定义的形式: 

var batch = {   
    map:{   
      callCount:0,   
      page:window.location.pathname + window.location.search,   
      httpSessionId:dwr.engine._getJSessionId(),   
      scriptSessionId:dwr.engine._getScriptSessionId()   
    },   
    charsProcessed:0, paramCount:0,   
    parameters:{}, headers:{},   
    isPoll:false, handlers:{}, preHooks:[], postHooks:[],   
    rpcType:dwr.engine._rpcType,   
    httpMethod:dwr.engine._httpMethod,   
    async:dwr.engine._async,   
    timeout:dwr.engine._timeout,   
    errorHandler:dwr.engine._errorHandler,   
    warningHandler:dwr.engine._warningHandler,   
    textHtmlHandler:dwr.engine._textHtmlHandler   
  };  
 这里面定义的形式类似于一个键一个值(举例textHtmlHandler键:dwr.engine._textHtmlHandler值),这也是javascript中创建一个对象的一种方式,我们也可以通过这种方式来创建,我们可以把这种方式想象成一个键对应一个值,这就是一个对象当中的属性和属性对应的值。也可以想象成dom编程的方式,也就是文档对象模型,为什么可以想象成文档对象模型呢,这就是元素和元素中的内容。怎么想象都可以,但是这种方式我们要注意学习学习。说说里面的内容,创建batch(批处理),批处理可能很多次都要调用到,所以需要一个变量callCount:0指定批处理中需要调用多少次,初始化为0;page是指定请求的页面,window.location.pathname只的是请求的路径,window.location.search指的是路径问号(?)后面的信息; httpSessionId就是JSESSIONID;scriptSessionId 脚本SessionId 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics