msgpack-java
It’s like JSON. but fast and small.
本文回答一下几个问题:
- 在Java中, msgpack如何实现打包,解包
- 在Java中,如何方便地实现对List, Map数据结构的序列化
- 在Java中,如果通讯双方类对象版本不统一,解包会有问题吗?
在Java中, msgpack如何实现打包,解包
java中打包,解包相当的容易。
引用msgpack包,包中有一个org.msgpack.annotation.Message的注解,带该注解的类即可实现打包和解包(序列化和反序列化)。
public class App
{
public static void main( String[] args )
{
MessagePack packer = new MessagePack();
A a = new A();
a.setiVal(10);
a.setsVal("Hello");
try {
byte[] adata = packer.write(a); // 打包(序列化)
A a2 = packer.read(adata , A.class); // 解包(反序列化)
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 带注解的类
@Message
class A{
private Integer iVal;
private String sVal;
public Integer getiVal() {
return iVal;
}
public void setiVal(Integer iVal) {
this.iVal = iVal;
}
public String getsVal() {
return sVal;
}
public void setsVal(String sVal) {
this.sVal = sVal;
}
}
在Java中,如何方便地实现对List, Map数据结构的序列化
如果需要简单的原生对象的List对象,可以使用Templates下面的方法,不过最简单的方式是把List, Map对象做为属性添加到具有Message注解的类中。例如:
@Message
class LA{
private List<A> as;
public List<A> getAs() {
return as;
}
public void setAs(List<A> as) {
this.as = as;
}
}
上面这个LA类就可以轻松实现List对象的序列化和反序列化,和普通类对象一样使用。
在Java中,如果通讯双方类对象版本不统一,解包会有问题吗?
这个问题,一般开始不会遇到。
众所周知,像XML, JSON这样的结构化数据有一个非常大的优点就是结构的稳定性非常好,对结构的修改不会引起老版本的问题。他们结构化的数据都是基于标签访问的,而msgpack是基于数据的。如果如前面的方法实现序列化,那么序列化/反序列化是基于数据的位置进行的,如果后期数据变更,很可能,数据就会存在问题。
经过测试,发现一下规律:
1. 如果两个类变量的顺序相同,其中一个类增加了变量,多了变量的类序列化出来的数据可以放序列化到变量少的类,反之也是可以的,但必需要求所有变量都是包装类变量(是Integer, 不是int),不然就报错。
2. 数组的数据不受此影响,数组元素必需适用规律1
3. Map是类似于JSON的数据存储方式,兼容性好,相当于把变量名称进行传输。
请看示例:
public class App
{
public static void main( String[] args )
{
MessagePack packer = new MessagePack();
A a = new A();
a.setiVal(10);
a.setsVal("Hello");
B b = new B();
b.setiVal(10);
b.setsVal("Hello");
b.setOk(true);
C c = new C();
c.setiVal(10);
c.setsVal("Hello");
LB lb = new LB();
List<B> as = new ArrayList<B>();
as.add(b);
B b1 = new B();
b1.setiVal(22);
b1.setsVal("Hellox");
b1.setOk(true);
as.add(b1);
lb.setAs(as);
MA ma = new MA();
HashMap<String, A> mamap = new HashMap<String, A>();
mamap.put("A", a);
mamap.put("B", a);
ma.setMap(mamap);
try {
byte[] adata = packer.write(a);
byte[] bdata = packer.write(b);
byte[] cdata = packer.write(c);
byte[] lbdata = packer.write(lb);
byte[] madata = packer.write(ma);
A a2 = packer.read(bdata, A.class); // 用类B的数据,反序列化A对象也是可以的
// A a3 = packer.read(cdata, A.class); // ERROR, C的数据编码格式和A的前半部分不同
LA la2 = packer.read(lbdata, LA.class); // 用类B 的List数据,可以反序列化LA的实例
MA ma2 = packer.read(madata, MA.class); // Map的适用性好
B b2 = packer.read(adata, B.class); // 如果变量都是类变量,A类的数据也可以放序列化
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Message
class A{
private Integer iVal;;
private String sVal;
public Integer getiVal() {
return iVal;
}
public void setiVal(Integer iVal) {
this.iVal = iVal;
}
public String getsVal() {
return sVal;
}
public void setsVal(String sVal) {
this.sVal = sVal;
}
}
@Message
class LA{
private List<A> as;
public List<A> getAs() {
return as;
}
public void setAs(List<A> as) {
this.as = as;
}
}
@Message
class MA{
private HashMap<String, A> map;
public HashMap<String, A> getMap() {
return map;
}
public void setMap(HashMap<String, A> map) {
this.map = map;
}
}
@Message
class B{
private Integer iVal;
private String sVal;
private Boolean isOk;
public Integer getiVal() {
return iVal;
}
public void setiVal(Integer iVal) {
this.iVal = iVal;
}
public String getsVal() {
return sVal;
}
public void setsVal(String sVal) {
this.sVal = sVal;
}
public Boolean isOk() {
return isOk;
}
public void setOk(Boolean isOk) {
this.isOk = isOk;
}
}
考虑兼容性,作为交互的数据类必需符合如下规则:
1. 类成员全部采用包装类
2. 一定定义好类,不能删除,修改,前中部插入类成员,只允许扩容
3. 对于数据变化较大的情况,考虑适用Map的方式更灵活。
在回答问题后,简要说明一下msgpack可以使用的场合。msgpack实现了多语言统一的序列化标准,从而可以实现在不同语言中实现结构化数据的交换。更为重要的是,msgpack有很多种语言的版本,这样跨语言的通讯就有了极大的优势。ActiveMQ通过JMS实现消息的序列化,JMS实质上也是一个标准话的数据结构。JSON也是标准话的结构,在JS王国中经常用到。阿里云的RocketMQ消息队列开源,并进入Apache孵化项目,它的消息内容是字节流,这意味着需要自己定义消息的格式。通过msgpack就可以方便的实现数据的交换。