GWT RPC 原理浅析二
2012-02-28 10:35
169 查看
前一篇介绍了RPC大体的流程,核心方法是RemoteServiceServlet类中的processPost方法
Java代码
public final void processPost(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException,
SerializationException {
// Read the request fully.
//
String requestPayload = readContent(request);
// Let subclasses see the serialized request.
//
onBeforeRequestDeserialized(requestPayload);
// Invoke the core dispatching logic, which returns the serialized
// result.
//
String responsePayload = processCall(requestPayload);
// Let subclasses see the serialized response.
//
onAfterResponseSerialized(responsePayload);
// Write the response.
//
writeResponse(request, response, responsePayload);
}
这是一个final方法,无法覆写。不过GWT为我们提供了前置后置方法,供我们覆写:
onBeforeRequestDeserialized 请求反序列化之前的处理
onAfterResponseSerialized 响应序列化之后的处理
下面我们深入这三个步骤
1. readContent(request)
这里调用了内部的一个方法
Java代码
protected String readContent(HttpServletRequest request)
throws ServletException, IOException {
return RPCServletUtils.readContentAsGwtRpc(request);
}
解析的工作由RPCServletUtils来处理,进入此方法
Java代码
public static String readContentAsGwtRpc(HttpServletRequest request)
throws IOException, ServletException {
return readContent(request, GWT_RPC_CONTENT_TYPE, CHARSET_UTF8);
}
调用了同名方法,添加了2个参数,分别是请求格式(text/x-gwt-rpc) 编码(utf-8)
进入
Java代码
public static String readContent(HttpServletRequest request,
String expectedContentType, String expectedCharSet)
throws IOException, ServletException {
if (expectedContentType != null) {
checkContentTypeIgnoreCase(request, expectedContentType);
}
if (expectedCharSet != null) {
checkCharacterEncodingIgnoreCase(request, expectedCharSet);
}
/*
* Need to support 'Transfer-Encoding: chunked', so do not rely on
* presence of a 'Content-Length' request header.
*/
InputStream in = request.getInputStream();
byte[] buffer = new byte[BUFFER_SIZE];
ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
try {
while (true) {
int byteCount = in.read(buffer);
if (byteCount == -1) {
break;
}
out.write(buffer, 0, byteCount);
}
String contentCharSet = expectedCharSet != null
? expectedCharSet : CHARSET_UTF8;
return out.toString(contentCharSet);
} finally {
if (in != null) {
in.close();
}
}
}
此处拿到request的输入流,并将内容转换为String类型返回。
至此readContent结束。
2. processCall(String payload)
处理这个请求的RPC调用
Java代码
public String processCall(String payload) throws SerializationException {
// First, check for possible XSRF situation
checkPermutationStrongName();
try {
RPCRequest rpcRequest = RPC.decodeRequest(payload, delegate.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
return RPC.invokeAndEncodeResponse(delegate, rpcRequest.getMethod(),
rpcRequest.getParameters(), rpcRequest.getSerializationPolicy(),
rpcRequest.getFlags());
} catch (IncompatibleRemoteServiceException ex) {
log(
"An IncompatibleRemoteServiceException was thrown while processing this call.",
ex);
return RPC.encodeResponseForFailure(null, ex);
}
}
RPC.decodeRequest()方法对提交上来的文本解析,生成一个RPCRequest对象
进入此方法
Java代码
public static RPCRequest decodeRequest(String encodedRequest, Class<?> type,
SerializationPolicyProvider serializationPolicyProvider) {
//….. 省略部分代码
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(
classLoader, serializationPolicyProvider);
streamReader.prepareToRead(encodedRequest);
//省略大量代码
//此处通过序列化读入流,解析文本,得出请求中需要调用的类名,方法名,已经方法签名数据 根据这些参数创建RPCRequest对象返回
return new RPCRequest(method, parameterValues, serializationPolicy,
streamReader.getFlags());
} catch (NoSuchMethodException e) {
throw new IncompatibleRemoteServiceException(
formatMethodNotFoundErrorMessage(serviceIntf, serviceMethodName,
parameterTypes));
}
} catch (SerializationException ex) {
throw new IncompatibleRemoteServiceException(ex.getMessage(), ex);
}
}
获得了RPCRequest对象后,通过RPC.invokeAndEncodeResponse()调用业务对象完成RPC
Java代码
public static String invokeAndEncodeResponse(Object target,
Method serviceMethod, Object[] args,
SerializationPolicy serializationPolicy, int flags)
throws SerializationException {
if (serviceMethod == null) {
throw new NullPointerException("serviceMethod");
}
if (serializationPolicy == null) {
throw new NullPointerException("serializationPolicy");
}
String responsePayload;
try {
//利用反射,完成对业务对象的调用
Object result = serviceMethod.invoke(target, args);
//把业务对象调用的返回结果序列化编码 并返回
responsePayload = encodeResponseForSuccess(serviceMethod, result,
serializationPolicy, flags);
} catch (IllegalAccessException e) {
SecurityException securityException = new SecurityException(
formatIllegalAccessErrorMessage(target, serviceMethod));
securityException.initCause(e);
throw securityException;
} catch (IllegalArgumentException e) {
SecurityException securityException = new SecurityException(
formatIllegalArgumentErrorMessage(target, serviceMethod, args));
securityException.initCause(e);
throw securityException;
} catch (InvocationTargetException e) {
// Try to encode the caught exception
//
Throwable cause = e.getCause();
responsePayload = encodeResponseForFailure(serviceMethod, cause,
serializationPolicy, flags);
}
return responsePayload;
}
拿到需要返回的序列化结果后,将其写入response
3. writeResponse
Java代码
private void writeResponse(HttpServletRequest request,
HttpServletResponse response, String responsePayload) throws IOException {
boolean gzipEncode = RPCServletUtils.acceptsGzipEncoding(request)
&& shouldCompressResponse(request, response, responsePayload);
RPCServletUtils.writeResponse(getServletContext(), response,
responsePayload, gzipEncode);
}
在写入response时,还判断浏览器是否支持gzip压缩,如果支持,则调用RPCServletUtils.writeResponse方法时,传参gzipEncod=true
当然内容还会判断,如果响应内容长度小于255,还是不会压缩的。
至此RPC整个请求响应完成
源自:http://jc-dreaming.iteye.com/blog/1096732
Java代码
public final void processPost(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException,
SerializationException {
// Read the request fully.
//
String requestPayload = readContent(request);
// Let subclasses see the serialized request.
//
onBeforeRequestDeserialized(requestPayload);
// Invoke the core dispatching logic, which returns the serialized
// result.
//
String responsePayload = processCall(requestPayload);
// Let subclasses see the serialized response.
//
onAfterResponseSerialized(responsePayload);
// Write the response.
//
writeResponse(request, response, responsePayload);
}
这是一个final方法,无法覆写。不过GWT为我们提供了前置后置方法,供我们覆写:
onBeforeRequestDeserialized 请求反序列化之前的处理
onAfterResponseSerialized 响应序列化之后的处理
下面我们深入这三个步骤
1. readContent(request)
这里调用了内部的一个方法
Java代码
protected String readContent(HttpServletRequest request)
throws ServletException, IOException {
return RPCServletUtils.readContentAsGwtRpc(request);
}
解析的工作由RPCServletUtils来处理,进入此方法
Java代码
public static String readContentAsGwtRpc(HttpServletRequest request)
throws IOException, ServletException {
return readContent(request, GWT_RPC_CONTENT_TYPE, CHARSET_UTF8);
}
调用了同名方法,添加了2个参数,分别是请求格式(text/x-gwt-rpc) 编码(utf-8)
进入
Java代码
public static String readContent(HttpServletRequest request,
String expectedContentType, String expectedCharSet)
throws IOException, ServletException {
if (expectedContentType != null) {
checkContentTypeIgnoreCase(request, expectedContentType);
}
if (expectedCharSet != null) {
checkCharacterEncodingIgnoreCase(request, expectedCharSet);
}
/*
* Need to support 'Transfer-Encoding: chunked', so do not rely on
* presence of a 'Content-Length' request header.
*/
InputStream in = request.getInputStream();
byte[] buffer = new byte[BUFFER_SIZE];
ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
try {
while (true) {
int byteCount = in.read(buffer);
if (byteCount == -1) {
break;
}
out.write(buffer, 0, byteCount);
}
String contentCharSet = expectedCharSet != null
? expectedCharSet : CHARSET_UTF8;
return out.toString(contentCharSet);
} finally {
if (in != null) {
in.close();
}
}
}
此处拿到request的输入流,并将内容转换为String类型返回。
至此readContent结束。
2. processCall(String payload)
处理这个请求的RPC调用
Java代码
public String processCall(String payload) throws SerializationException {
// First, check for possible XSRF situation
checkPermutationStrongName();
try {
RPCRequest rpcRequest = RPC.decodeRequest(payload, delegate.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
return RPC.invokeAndEncodeResponse(delegate, rpcRequest.getMethod(),
rpcRequest.getParameters(), rpcRequest.getSerializationPolicy(),
rpcRequest.getFlags());
} catch (IncompatibleRemoteServiceException ex) {
log(
"An IncompatibleRemoteServiceException was thrown while processing this call.",
ex);
return RPC.encodeResponseForFailure(null, ex);
}
}
RPC.decodeRequest()方法对提交上来的文本解析,生成一个RPCRequest对象
进入此方法
Java代码
public static RPCRequest decodeRequest(String encodedRequest, Class<?> type,
SerializationPolicyProvider serializationPolicyProvider) {
//….. 省略部分代码
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(
classLoader, serializationPolicyProvider);
streamReader.prepareToRead(encodedRequest);
//省略大量代码
//此处通过序列化读入流,解析文本,得出请求中需要调用的类名,方法名,已经方法签名数据 根据这些参数创建RPCRequest对象返回
return new RPCRequest(method, parameterValues, serializationPolicy,
streamReader.getFlags());
} catch (NoSuchMethodException e) {
throw new IncompatibleRemoteServiceException(
formatMethodNotFoundErrorMessage(serviceIntf, serviceMethodName,
parameterTypes));
}
} catch (SerializationException ex) {
throw new IncompatibleRemoteServiceException(ex.getMessage(), ex);
}
}
获得了RPCRequest对象后,通过RPC.invokeAndEncodeResponse()调用业务对象完成RPC
Java代码
public static String invokeAndEncodeResponse(Object target,
Method serviceMethod, Object[] args,
SerializationPolicy serializationPolicy, int flags)
throws SerializationException {
if (serviceMethod == null) {
throw new NullPointerException("serviceMethod");
}
if (serializationPolicy == null) {
throw new NullPointerException("serializationPolicy");
}
String responsePayload;
try {
//利用反射,完成对业务对象的调用
Object result = serviceMethod.invoke(target, args);
//把业务对象调用的返回结果序列化编码 并返回
responsePayload = encodeResponseForSuccess(serviceMethod, result,
serializationPolicy, flags);
} catch (IllegalAccessException e) {
SecurityException securityException = new SecurityException(
formatIllegalAccessErrorMessage(target, serviceMethod));
securityException.initCause(e);
throw securityException;
} catch (IllegalArgumentException e) {
SecurityException securityException = new SecurityException(
formatIllegalArgumentErrorMessage(target, serviceMethod, args));
securityException.initCause(e);
throw securityException;
} catch (InvocationTargetException e) {
// Try to encode the caught exception
//
Throwable cause = e.getCause();
responsePayload = encodeResponseForFailure(serviceMethod, cause,
serializationPolicy, flags);
}
return responsePayload;
}
拿到需要返回的序列化结果后,将其写入response
3. writeResponse
Java代码
private void writeResponse(HttpServletRequest request,
HttpServletResponse response, String responsePayload) throws IOException {
boolean gzipEncode = RPCServletUtils.acceptsGzipEncoding(request)
&& shouldCompressResponse(request, response, responsePayload);
RPCServletUtils.writeResponse(getServletContext(), response,
responsePayload, gzipEncode);
}
在写入response时,还判断浏览器是否支持gzip压缩,如果支持,则调用RPCServletUtils.writeResponse方法时,传参gzipEncod=true
当然内容还会判断,如果响应内容长度小于255,还是不会压缩的。
至此RPC整个请求响应完成
源自:http://jc-dreaming.iteye.com/blog/1096732
相关文章推荐
- GWT RPC 原理浅析一
- Google GWT的RPC原理浅析
- 【新手】浅析比特币、区块链原理。值钱 分布式 链式存储数据库 记账 以太坊
- 驱动层与应用层的事件同步(主动防御原理浅析)
- 从零开始实现RPC框架 - RPC原理及实现
- Laravel Auth原理浅析。
- 你应该知道的 RPC 原理
- Rpc原理与实现
- Mongo 主从复制 原理浅析
- HTTP长连接和短连接原理浅析
- Windows 7密码重设盘的内部原理浅析
- iPhone的Push(推送通知)功能原理浅析
- ASP.NET 中 Session 实现原理浅析 [1] 会话的建立流程
- Android框架浅析之锁屏(Keyguard)机制原理
- 浅析 Linux 中的时间编程和实现原理,第 2 部分: 硬件和 GLibC 库的细节
- 浅析静态库链接原理
- 浅析c++函数重载的原理
- [置顶] js原生Ajax 的封装和原理之浅析
- STM32 基于串口RS485双机通信原理浅析
- C# 2.0 中Iterators的改进与实现原理浅析