MessagePack 是一个高效的二进制数据序列化工具. 使用它可以让你像使用JSON那样在多种语言中进行数据交换, 但是它比JSON更加小巧,迅捷.
在Java中使用的话, 我们首先添加maven依赖
1 2 3 4 5 <dependency > <groupId > org.msgpack</groupId > <artifactId > msgpack</artifactId > <version > 0.6.12</version > </dependency >
首先看一个简单的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import org.msgpack.MessagePack;import org.msgpack.annotation.Message;public class Main1 { @Message public static class MyMessage { public String name; public double version; } public static void main (String[] args) throws Exception { MyMessage src = new MyMessage(); src.name = "msgpack" ; src.version = 0.6 ; MessagePack msgpack = new MessagePack(); byte [] bytes = msgpack.write(src); MyMessage dst = msgpack.read(bytes, MyMessage.class); } }
在上面的例子中我们看到将一个MyMessage
序列化成byte数组, 同时又将其反序列化出来了. 但是如果我们要同时序列化多个对象呢?那么我们就可以使用Packer
和Unpacker
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import org.msgpack.MessagePack;import org.msgpack.annotation.Message;import org.msgpack.packer.Packer;import org.msgpack.unpacker.Unpacker;public class Main2 { @Message public static class MyMessage { public String name; public double version; } public static void main (String[] args) throws Exception { MyMessage src1 = new MyMessage(); src1.name = "msgpack" ; src1.version = 0.6 ; MyMessage src2 = new MyMessage(); src2.name = "muga" ; src2.version = 10.0 ; MyMessage src3 = new MyMessage(); src3.name = "frsyukik" ; src3.version = 1.0 ; MessagePack msgpack = new MessagePack(); ByteArrayOutputStream out = new ByteArrayOutputStream(); Packer packer = msgpack.createPacker(out); packer.write(src1); packer.write(src2); packer.write(src3); byte [] bytes = out.toByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); Unpacker unpacker = msgpack.createUnpacker(in); MyMessage dst1 = unpacker.read(MyMessage.class); MyMessage dst2 = unpacker.read(MyMessage.class); MyMessage dst3 = unpacker.read(MyMessage.class); } }
其实Packer
和Unpacker
内置了非常多了序列化类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.math.BigInteger;import java.nio.ByteBuffer;import org.msgpack.MessagePack;import org.msgpack.packer.Packer;import org.msgpack.unpacker.Unpacker;public class Main3 { public static void main (String[] args) throws Exception { MessagePack msgpack = new MessagePack(); ByteArrayOutputStream out = new ByteArrayOutputStream(); Packer packer = msgpack.createPacker(out); packer.write(true ); packer.write(10 ); packer.write(10.5 ); packer.write(Boolean.TRUE); packer.write(new Integer(10 )); packer.write(new Double(10.5 )); packer.write(new int [] { 1 , 2 , 3 , 4 }); packer.write(new Double[] { 10.5 , 20.5 }); packer.write(new String[] { "msg" , "pack" , "for" , "java" }); packer.write(new byte [] { 0x30 , 0x31 , 0x32 }); packer.write("MessagePack" ); packer.write(ByteBuffer.wrap(new byte [] { 0x30 , 0x31 , 0x32 })); packer.write(BigInteger.ONE); byte [] bytes = out.toByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); Unpacker unpacker = msgpack.createUnpacker(in); boolean b = unpacker.readBoolean(); int i = unpacker.readInt(); double d = unpacker.readDouble(); Boolean wb = unpacker.read(Boolean.class); Integer wi = unpacker.read(Integer.class); Double wd = unpacker.read(Double.class); int [] ia = unpacker.read(int [].class); Double[] da = unpacker.read(Double[].class); String[] sa = unpacker.read(String[].class); byte [] ba = unpacker.read(byte [].class); String ws = unpacker.read(String.class); ByteBuffer buf = unpacker.read(ByteBuffer.class); BigInteger bi = unpacker.read(BigInteger.class); } }
对于List, Map
这俩种类型的序列化, 我们需要额外说明一下. 在序列化List, Map
的时候, 我们需要使用Template
对其进行转换.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.util.*;import org.msgpack.MessagePack;import org.msgpack.packer.Packer;import org.msgpack.template.Template;import org.msgpack.unpacker.Unpacker;import static org.msgpack.template.Templates.tList;import static org.msgpack.template.Templates.tMap;import static org.msgpack.template.Templates.TString;public class Main4 { public static void main (String[] args) throws Exception { MessagePack msgpack = new MessagePack(); Template<List<String>> listTmpl = tList(TString); Template<Map<String, String>> mapTmpl = tMap(TString, TString); ByteArrayOutputStream out = new ByteArrayOutputStream(); Packer packer = msgpack.createPacker(out); List<String> list = new ArrayList<String>(); list.add("msgpack" ); list.add("for" ); list.add("java" ); packer.write(list); Map<String, String> map = new HashMap<String, String>(); map.put("sadayuki" , "furuhashi" ); map.put("muga" , "nishizawa" ); packer.write(map); byte [] bytes = out.toByteArray(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); Unpacker unpacker = msgpack.createUnpacker(in); List<String> dstList = unpacker.read(listTmpl); Map<String, String> dstMap = unpacker.read(mapTmpl); } }
有时候我们可能没有办法将POJO类添加上Message
注解(可能没有访问那个类的权限), 但是我们又想对其进行序列化, 那怎么办呢?
1 2 MessagePack msgpack = new MessagePack(); msgpack.register(MyMessage2.class);
我们只要向需要序列化的类注册到MessagePack
上就可以了.
有时候,我们可能不需要对某个属性进行序列化, 例如线上某个老版本里并没有A属性, 但是在新的版本里填上了A属性, 但是又要兼容老版本怎么办呢?我们可以使用@Optional
注解
1 2 3 4 5 6 7 8 9 @Message public static class MyMessage { public String name; public double version; @Optional public int flag = 0 ; }
MessagePack还提供了动态类型特性.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.*;import org.msgpack.MessagePack;import org.msgpack.type.Value;import org.msgpack.unpacker.Converter;import static org.msgpack.template.Templates.*;public class Main5 { public static void main (String[] args) throws Exception { List<String> src = new ArrayList<String>(); src.add("msgpack" ); src.add("kumofs" ); src.add("viver" ); MessagePack msgpack = new MessagePack(); byte [] raw = msgpack.write(src); List<String> dst1 = msgpack.read(raw, tList(TString)); Value dynamic = msgpack.read(raw); List<String> dst2 = new Converter(dynamic).read(tList(TString)); } }
当从MessagePack里读取数据的时候, 我们可以先不指定其转换的类型, 使用Value
来代替, 等后期我们再使用Converter
对其转换.
接下来我们对其与JSON进行对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class msgpack { public static void main (String[] args) throws Exception { MessagePack msgpack = new MessagePack(); List<SeObj> list = list(); long start1 = System.currentTimeMillis(); byte [] bytes1 = msgpack.write(list); long end1 = System.currentTimeMillis(); System.out.println((end1 - start1) + " : " + bytes1.length); long start2 = System.currentTimeMillis(); String json = JSON.toJSONString(list); long end2 = System.currentTimeMillis(); System.out.println((end2 - start2) + " : " + json.getBytes().length); } public static List<SeObj> list () { List<SeObj> list = new ArrayList<>(); Random random = new Random(); for (int i = 0 ; i < 10000 ; i++) { SeObj seObj = new SeObj(); seObj.id = random.nextInt(100000 ); seObj.tall = random.nextFloat(); seObj.name = "name" + random.nextInt(100000 ); list.add(seObj); } return list; } } @Message class SeObj { public int id; public String name; public float tall; }
结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 100 的结果194 : 1960 50 : 4947 1000 的结果210 : 19589 70 : 49424 10000 的结果212 : 195765 160 : 493987 100000 的结果283 : 1956964 330 : 4940270 1000000 的结果649 : 19573508 1878 : 49404120
我们发现MessagePack的耗时相对来说是比较稳定的, 但是在生成的数据量上比JSON要强一倍多