GWT RPC 原理浅析二

前一篇介绍了RPC大体的流程,核心方法是RemoteServiceServlet类中的processPost方法

Java代码   收藏代码
  1. public final void processPost(HttpServletRequest request,  
  2.       HttpServletResponse response) throws IOException, ServletException,  
  3.       SerializationException {  
  4.     // Read the request fully.  
  5.     //  
  6.     String requestPayload = readContent(request);  
  7.   
  8.     // Let subclasses see the serialized request.  
  9.     //  
  10.     onBeforeRequestDeserialized(requestPayload);  
  11.   
  12.     // Invoke the core dispatching logic, which returns the serialized  
  13.     // result.  
  14.     //  
  15.     String responsePayload = processCall(requestPayload);  
  16.   
  17.     // Let subclasses see the serialized response.  
  18.     //  
  19.     onAfterResponseSerialized(responsePayload);  
  20.   
  21.     // Write the response.  
  22.     //  
  23.     writeResponse(request, response, responsePayload);  
  24.   }  


这是一个final方法,无法覆写。不过GWT为我们提供了前置后置方法,供我们覆写:
onBeforeRequestDeserialized 请求反序列化之前的处理
onAfterResponseSerialized 响应序列化之后的处理

下面我们深入这三个步骤
1. readContent(request)
这里调用了内部的一个方法
Java代码   收藏代码
  1. protected String readContent(HttpServletRequest request)  
  2.       throws ServletException, IOException {  
  3.     return RPCServletUtils.readContentAsGwtRpc(request);  
  4.   }  

解析的工作由RPCServletUtils来处理,进入此方法

Java代码   收藏代码
  1. public static String readContentAsGwtRpc(HttpServletRequest request)  
  2.       throws IOException, ServletException {  
  3.       return readContent(request, GWT_RPC_CONTENT_TYPE, CHARSET_UTF8);  
  4.   }  

调用了同名方法,添加了2个参数,分别是请求格式(text/x-gwt-rpc) 编码(utf-8)
进入

Java代码   收藏代码
  1. public static String readContent(HttpServletRequest request,  
  2.       String expectedContentType, String expectedCharSet)  
  3.       throws IOException, ServletException {  
  4.     if (expectedContentType != null) {  
  5.       checkContentTypeIgnoreCase(request, expectedContentType);  
  6.     }  
  7.     if (expectedCharSet != null) {  
  8.       checkCharacterEncodingIgnoreCase(request, expectedCharSet);  
  9.     }  
  10.   
  11.     /* 
  12.      * Need to support 'Transfer-Encoding: chunked', so do not rely on 
  13.      * presence of a 'Content-Length' request header. 
  14.      */  
  15.     InputStream in = request.getInputStream();  
  16.     byte[] buffer = new byte[BUFFER_SIZE];  
  17.     ByteArrayOutputStream out = new  ByteArrayOutputStream(BUFFER_SIZE);  
  18.     try {  
  19.       while (true) {  
  20.         int byteCount = in.read(buffer);  
  21.         if (byteCount == -1) {  
  22.           break;  
  23.         }  
  24.         out.write(buffer, 0, byteCount);  
  25.       }  
  26.       String contentCharSet = expectedCharSet != null  
  27.           ? expectedCharSet : CHARSET_UTF8;  
  28.       return out.toString(contentCharSet);  
  29.     } finally {  
  30.       if (in != null) {  
  31.         in.close();  
  32.       }  
  33.     }  
  34.   }  


此处拿到request的输入流,并将内容转换为String类型返回。
至此readContent结束。
2. processCall(String payload)
处理这个请求的RPC调用

Java代码   收藏代码
  1. public String processCall(String payload) throws SerializationException {  
  2.     // First, check for possible XSRF situation  
  3.     checkPermutationStrongName();  
  4.   
  5.     try {  
  6.       RPCRequest rpcRequest = RPC.decodeRequest(payload, delegate.getClass(), this);  
  7.       onAfterRequestDeserialized(rpcRequest);  
  8.       return RPC.invokeAndEncodeResponse(delegate, rpcRequest.getMethod(),  
  9.           rpcRequest.getParameters(), rpcRequest.getSerializationPolicy(),  
  10.           rpcRequest.getFlags());  
  11.     } catch (IncompatibleRemoteServiceException ex) {  
  12.       log(  
  13.           "An IncompatibleRemoteServiceException was thrown while processing this call.",  
  14.           ex);  
  15.       return RPC.encodeResponseForFailure(null, ex);  
  16.     }  
  17.   }  

RPC.decodeRequest()方法对提交上来的文本解析,生成一个RPCRequest对象
进入此方法

Java代码   收藏代码
  1. public static RPCRequest decodeRequest(String encodedRequest, Class<?> type,  
  2.       SerializationPolicyProvider serializationPolicyProvider) {  
  3.      
  4.     //….. 省略部分代码  
  5.     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  
  6.   
  7.     try {  
  8.       ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(  
  9.           classLoader, serializationPolicyProvider);  
  10.       streamReader.prepareToRead(encodedRequest);  
  11.   
  12.      //省略大量代码  
  13. //此处通过序列化读入流,解析文本,得出请求中需要调用的类名,方法名,已经方法签名数据 根据这些参数创建RPCRequest对象返回  
  14.   
  15.         return new RPCRequest(method, parameterValues, serializationPolicy,  
  16.             streamReader.getFlags());  
  17.   
  18.       } catch (NoSuchMethodException e) {  
  19.         throw new IncompatibleRemoteServiceException(  
  20.             formatMethodNotFoundErrorMessage(serviceIntf, serviceMethodName,  
  21.                 parameterTypes));  
  22.       }  
  23.     } catch (SerializationException ex) {  
  24.       throw new IncompatibleRemoteServiceException(ex.getMessage(), ex);  
  25.     }  
  26.   }  

获得了RPCRequest对象后,通过RPC.invokeAndEncodeResponse()调用业务对象完成RPC
Java代码   收藏代码
  1. public static String invokeAndEncodeResponse(Object target,  
  2.       Method serviceMethod, Object[] args,  
  3.       SerializationPolicy serializationPolicy, int flags)  
  4.       throws SerializationException {  
  5.     if (serviceMethod == null) {  
  6.       throw new NullPointerException("serviceMethod");  
  7.     }  
  8.   
  9.     if (serializationPolicy == null) {  
  10.       throw new NullPointerException("serializationPolicy");  
  11.     }  
  12.   
  13.     String responsePayload;  
  14. try {  
  15. //利用反射,完成对业务对象的调用  
  16.       Object result = serviceMethod.invoke(target, args);  
  17. //把业务对象调用的返回结果序列化编码 并返回  
  18.       responsePayload = encodeResponseForSuccess(serviceMethod, result,  
  19.           serializationPolicy, flags);  
  20.     } catch (IllegalAccessException e) {  
  21.       SecurityException securityException = new SecurityException(  
  22.           formatIllegalAccessErrorMessage(target, serviceMethod));  
  23.       securityException.initCause(e);  
  24.       throw securityException;  
  25.     } catch (IllegalArgumentException e) {  
  26.       SecurityException securityException = new SecurityException(  
  27.           formatIllegalArgumentErrorMessage(target, serviceMethod, args));  
  28.       securityException.initCause(e);  
  29.       throw securityException;  
  30.     } catch (InvocationTargetException e) {  
  31.       // Try to encode the caught exception  
  32.       //  
  33.       Throwable cause = e.getCause();  
  34.   
  35.       responsePayload = encodeResponseForFailure(serviceMethod, cause,  
  36.           serializationPolicy, flags);  
  37.     }  
  38.   
  39.     return responsePayload;  
  40.   }  

拿到需要返回的序列化结果后,将其写入response
3. writeResponse
Java代码   收藏代码
  1. private void writeResponse(HttpServletRequest request,  
  2.       HttpServletResponse response, String responsePayload) throws IOException {  
  3.     boolean gzipEncode = RPCServletUtils.acceptsGzipEncoding(request)  
  4.         && shouldCompressResponse(request, response, responsePayload);  
  5.   
  6.     RPCServletUtils.writeResponse(getServletContext(), response,  
  7.         responsePayload, gzipEncode);  
  8.   }  


在写入response时,还判断浏览器是否支持gzip压缩,如果支持,则调用RPCServletUtils.writeResponse方法时,传参gzipEncod=true
当然内容还会判断,如果响应内容长度小于255,还是不会压缩的。

至此RPC整个请求响应完成


                                                                                                    源自:http://jc-dreaming.iteye.com/blog/1096732


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值