对象序列化工具,集合了json和protobuf的优点,既灵活又有效率。源码地址:http://git.oschina.net/yunaibao/MessageBox
全新的序列化工具,参考json和protobuf实现的一个即具有灵活性也具有效率的序列化工具(这是一种折中策略,将json和protobuf两者优点有点平均)
经过测试,性能已经超过protostuff-runtime这个序列化工具
支持基本数据类型和基本数据类型的包装类型 以及 Enum 、Collection 、Map 、Date 、Calendar 、自定义的消息结构体(必须实现IMessage接口)
序列化的消息必须实现IMessage接口,消息体内支持Object类型的字段,字段值实际类型 可以是 基本类型或者Eum Collection Map等当前序列化工具所支持的类型 ,不支持Object类型
序列化: byte[] data = MessageBox.toBytes(object); 反序列化: MessageBox.parse(clazz, data);
具体使用,请参考项目中的test源码
目前只支持java
需要大家先测试java版,提交意见,完善java版之后,会出C#版
测试时,应当先执行序列化一遍,因为第一次序列化,会通过反射创建对象Schema,所以第一次序列化比较耗时,如果测试会有误差
不求赞,只求测试给意见和建议
-- 这里还是写一下例子吧
Message定义 :
Message必须实现IMessage接口,所有要序列化的字段必须标有@Member(tag) 注解,tag是字段的唯一int类型的标识
import java.util.Collection;
import java.util.Map;
import com.ynb.msgbox.IMessage;
import com.ynb.msgbox.annotation.Member;
@SuppressWarnings("rawtypes")
public class TestMessage implements IMessage{
@Member(1)
public TestEnum a;
@Member(2)
public int b;
@Member(3)
public int c;
@Member(4)
private Map map;
@Member(5)
private Map<String,Object> map2;
@Member(6)
private Collection<Object> collect;
@Member(7)
private Collection<Long> collect2;
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Map<String, Object> getMap2() {
return map2;
}
public void setMap2(Map<String, Object> map2) {
this.map2 = map2;
}
public Collection<?> getCollect() {
return collect;
}
public Collection<Long> getCollect2() {
return collect2;
}
public void setCollect2(Collection<Long> collect2) {
this.collect2 = collect2;
}
public void setCollect(Collection<Object> collect) {
this.collect = collect;
}
}
序列化和反序列化的使用
TestMessage msg = new TestMessage();
msg.a = TestEnum.c;
msg.b = 2;
msg.c = 1010;
msg.setCollect(coll1);
msg.setCollect2(coll2);
msg.setMap(map);
msg.setMap2(map2);
// 测试序列化消息体
byte[] bytes = MessageBox.toBytes(msg);
// 测试反序列化消息体
MessageBox.parse(TestMessage.class,bytes);
数据容器向消息体转换
MessageBox msgBox = new MessageBox();
msgBox.setAttr(1, TestEnum.a);
msgBox.setAttr(2, 123123);
msgBox.setAttr(3, 3);
//将msgBox数据容器转换为TestMessage对象
msgBox.toMessage(TestMessage.class);
不明确类型的反序列化
如果序列化一个对象得到数据后,对方并不知道这个对象的具体类型,那么此时使用 MessageBox.parse(bytes); 可以得到一个默认类型的数据
源类型 | 反序列化后的类型 |
---|
byte | byte |
short | short |
int | int |
long | long |
float | float |
double | double |
LinkedList,HashSet... | ArrayList |
ConcurrentHashMap,LinkedHahsMap... | HashMap |
MessageBox,other Message | MessageBox |
Enum | int |
多维数组 | 最后维度数组的组件类型为Object的多维数组(如:int[][][] 转为 Object[][][]) |
TestMessage msg = new TestMessage();
msg.a = TestEnum.c;
msg.b = 2;
msg.c = 1010;
msg.setCollect(coll1);
msg.setCollect2(coll2);
msg.setMap(map);
msg.setMap2(map2);
// 序列化消息体
byte[] bytes = MessageBox.toBytes(msg);
// 反序列化
MessageBox.parse(bytes);
字段类型不明确的序列化和反序列化
当Message中存在Object类型,该类型是不明确的,因此在序列化时,根据这个字段的值的实际类型o.getClass()来查找指定的Schema进行序列化操作
而明确类型的字段的Schema都在创建当前Message的Schema时已经查找并存起来,用以提高序列化效率
无论字段类型是否明确,都会将字段标注的@Member(tag) 和字段值的真实类型的基本类型id进行位运算写入到IO中
序列化后得到的数据,如果再反序列化时,因为字段类型不明确,会根据读到的tag解析出字段原有的基本类型id,再根据这个基本类型查找基本类型的Schema进行反序列化,此时就得到的是一个基本类型的值,参考上表
stirng序列化的优化
string 本身有getBytes()功能,但是原理是copy char[] 到charbuffer中,然后再创建bytebuffer,将这两个交给指定的编码器编码,
编码器编码时,解出每个char的指定编码格式的代码点,写入bytebuffer中,这个过程就已经存在了一个char[]数组的复制,和bytebuffer中初始化一定长度的byte[]数组
还有就是每次写入bytebuffer中,有可能也存在数组复制。当写入完毕,bytebuffer调用arry()方法,将bytebuffer中缓存的数据copy出来,再写入外部的IO中
这整个过程就存在了多次的数组复制,因此为了提高效率,此工具重写了UTF8的编码,直接嵌入到IO层,避免数组多次复制,因此提高了不少的性能