motan源码分析七:序列化
motan的序列化支持两种协议,一种是json,另一种是hessian2。主要涉及到的类和接口是是:FastJsonSerialization、Hessian2Serialization、Serialization、Codec、AbstractCodec、NettyDecoder、NettyEncoder、DefaultRpcCodec和CompressRpcCodec等。
1.FastJsonSerialization使用json作为数据交换协议,Hessian2Serialization使用hessian2作为数据交换协议
@SpiMeta(name = "hessian2")
public class Hessian2Serialization implements Serialization { @Override
public byte[] serialize(Object data) throws IOException {//使用hessan2进行序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output out = new Hessian2Output(bos);
out.writeObject(data);
out.flush();
return bos.toByteArray();
} @SuppressWarnings("unchecked")
@Override
public <T> T deserialize(byte[] data, Class<T> clz) throws IOException {//使用hessan2进行反序列化
Hessian2Input input = new Hessian2Input(new ByteArrayInputStream(data));
return (T) input.readObject(clz);
}
}
2.motan支持压缩和非压缩两种方式
public byte[] encode(Channel channel, Object message) throws IOException {
if (needEncodeV1(message)) {//判断使用哪个版本的encode,decode同样
return v1Codec.encode(channel, message);
} else {
// 使用v2压缩版本
return encodeV2(channel, message);//使用压缩版本的encode
}
}
public byte[] encodeV2(Channel channel, Object message) throws IOException {
try {
if (message instanceof Request) {
return encodeRequest(channel, (Request) message);//序列化并压缩request对象
} else if (message instanceof Response) {
return encodeResponse(channel, (Response) message);//序列化并压缩response对象
}
} catch (Exception e) {
if (ExceptionUtil.isMotanException(e)) {
throw (RuntimeException) e;
} else {
throw new MotanFrameworkException("encode error: isResponse=" + (message instanceof Response), e,
MotanErrorMsgConstant.FRAMEWORK_ENCODE_ERROR);
}
}
throw new MotanFrameworkException("encode error: message type not support, " + message.getClass(),
MotanErrorMsgConstant.FRAMEWORK_ENCODE_ERROR);
}
private byte[] encodeRequest(Channel channel, Request request) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutput output = createOutput(outputStream);
addMethodInfo(output, request);
//拿到hessian2或fasjson处理对象
Serialization serialization =
ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(
channel.getUrl().getParameter(URLParamType.serialize.getName(), URLParamType.serialize.getValue()));
if (request.getArguments() != null && request.getArguments().length > 0) {
for (Object obj : request.getArguments()) {
serialize(output, obj, serialization);//序列化
}
}
if (request.getAttachments() == null || request.getAttachments().isEmpty()) {
// empty attachments
output.writeShort(0);
} else {
// 需要copy一份attachment进行签名替换,这样在失败重试时原始的request信息不会变更
Map<String, String> attachments = copyMap(request.getAttachments());
replaceAttachmentParamsBySign(channel, attachments);
addAttachment(output, attachments);
}
output.flush();
byte[] body = outputStream.toByteArray();
byte flag = MotanConstants.FLAG_REQUEST;
output.close();
Boolean usegz = channel.getUrl().getBooleanParameter(URLParamType.usegz.getName(), URLParamType.usegz.getBooleanValue());
int minGzSize = channel.getUrl().getIntParameter(URLParamType.mingzSize.getName(), URLParamType.mingzSize.getIntValue());
return encode(compress(body, usegz, minGzSize), flag, request.getRequestId());//压缩处理
}
3.通过NettyDecoder和NettyEncoder与netty框架进行结合
protected Object encode(ChannelHandlerContext ctx, Channel nettyChannel, Object message) throws Exception {
long requestId = getRequestId(message);//获取requestId
byte[] data = null;
if (message instanceof Response) {
try {
data = codec.encode(client, message);
} catch (Exception e) {
LoggerUtil.error("NettyEncoder encode error, identity=" + client.getUrl().getIdentity(), e);
Response response = buildExceptionResponse(requestId, e);
data = codec.encode(client, response);
}
} else {
data = codec.encode(client, message);//调用DefaultRpcCodec或压缩的codec来编码
}
byte[] transportHeader = new byte[MotanConstants.NETTY_HEADER];
ByteUtil.short2bytes(MotanConstants.NETTY_MAGIC_TYPE, transportHeader, 0);
transportHeader[3] = getType(message);
ByteUtil.long2bytes(getRequestId(message), transportHeader, 4);
ByteUtil.int2bytes(data.length, transportHeader, 12);
return ChannelBuffers.wrappedBuffer(transportHeader, data);
}
motan源码分析七:序列化的更多相关文章
- motan源码分析六:客户端与服务器的通信层分析
本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...
- ABP源码分析七:Setting 以及 Mail
本文主要说明Setting的实现以及Mail这个功能模块如何使用Setting. 首先区分一下ABP中的Setting和Configuration. Setting一般用于需要通过外部配置文件(或数据 ...
- vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...
- Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解
先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...
- motan源码分析八:涉及到底层的客户端调用
之前我们分析了客户端调用服务端的源码,但是没有涉及到通讯层和序列化层,本文将之前讲过的内容做一次串联. 1.上层通过动态代理调用refer的call,每个refer又对应一个nettyclient,下 ...
- motan源码分析十一:部分特性
本章将描述motan部分的特性并对源码进行分析. 1.requestid的维护,使用了当前时间左移20位,再和一个自增变量组合 public class RequestIdGenerator { ); ...
- motan源码分析十:流量切换
motan提供了流量切换的功能,可以实现把一个group的流量切换到另一个group(一个或多个服务都可以).大家可以使用tomcat部署motan的管理工具,并设置几个组,例如可以参考demo代码: ...
- motan源码分析五:cluster相关
上一章我们分析了客户端调用服务端相关的源码,但是到了cluster里面的部分我们就没有分析了,本章将深入分析cluster和它的相关支持类. 1.clustersupport的创建过程,上一章的Ref ...
- motan源码分析二:使用spi机制进行类加载
在motan的源码中使用了很多的spi机制进行对象的创建,下面我们来具体分析一下它的实现方法. 1.在实际的jar包的\META-INF\services目录中引入相关的文件,例如下图中,我解压了co ...
随机推荐
- 启动php-fpm时报错
[root@localhost ~]# /usr/local/php/sbin/php-fpm [06-Aug-2012 19:17:53] ALERT: [pool www] pm.min_spar ...
- 查看library_cache 库缓冲区的命中率
关于library cache的命中率: SQL> desc V$librarycache NAMESPACE ...
- iOS横竖屏切换的一些坑(持续更新)
最近在做视频类的App,遇到视频滚动播放的坑,紧接着就是横竖屏问题.之前太过天真不想做横竖屏配置.只是想旋转视频View,但是分享什么的包括AlertView还是竖屏样式,项目着急上线(1周提交一次也 ...
- MySQL 管理
MySQL 管理 启动及关闭 MySQL 服务器 首先,我们需要通过以下命令来检查MySQL服务器是否启动: ps -ef | grep mysqld 如果MySql已经启动,以上命令将输出mysql ...
- SSM框架入门和搭建 十部曲
又快到毕业设计的时候了,有的学弟说想用ssm做毕业设计,在网上找到资料看不懂,基础差.我就帮他写了一个demo,顺便也整理一下. SSM框架,顾名思义,就是Spring+SpringMVC+mybat ...
- 解决jQuery插件sliderjs, 点击插件分页,导航按钮后不能重新开始.
jQuery SlidesJS - Can't restart animation after clicking on navigation or pagination <!DOCTYPE ht ...
- ejabberd,erlang,简单看了一下,总结一下,很肤浅
本来也没打算深入学习erlang,就是看一下他们的大概思路erlang每个自定义函数都能注册成进程,每个节点通过erl -name 'name@ip'.进去后,可以直接做远程调用,节点之间就靠一个连接 ...
- javascript 字符串滚动显示
<html> <head> <script type="text/javascript"> var chars = "JavaScri ...
- 移动H5前端性能优化指南[托尼托尼研究所]
概述 1. PC优化手段在Mobile侧同样适用2. 在Mobile侧我们提出三秒种渲染完成首屏指标3. 基于第二点,首屏加载3秒完成或使用Loading4. 基于联通3G网络平均338KB/s(2. ...
- ucenter 通信原理
1.用户登录discuz,通过logging.php文件中的函数uc_user_login对post过来的数据进行验证,也就是对username和password进行验证. 2.如果验证成功,将调用位 ...