在我们的开发过程中,序列化是经常需要处理的问题,比如在做分布式访问数据时,或者是在做redis缓存存储数据时,如果我们涉及的知识面不够广的话,可能会简单的使用JDK的序列化,也即在需要序列化的类上implements Serializable接口去实现序列化,我想说的是这种方式在小系统中尚且可以用一用,如果是并发很大的系统会受到严重影响,这是由于JDK自带的序列化效率很低,不论是时间上还是空间上。我们经常使用的序列化方式还有XML和Json,说实在的我更多的是使用Json,我觉得它很方便很友好,但这些都不够好,我今天要将的是google开发的开源的序列化方案protocol buffer(简称protobuf),它的好处很多,独立于语言,独立于平台,最最重要的是它的效率相当高,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一,是不是很心动。其实我也刚接触这个好东西,写下此篇博客就当一个学习笔记吧。

protobuf使用起来非常简单,它的主要流程是:我们需要自己写一个.proto文件用来描述序列化的格式,然后用protobuf提供的protoc工具将.proto文件编译成一个Java文件(protobuf官方支持很多语言:Java、C++、C#、Go、Python ,protobuf是一个开源项目,因此有很多大牛也实现了其他语言,但它们的可靠性还有待验证),最后将该Java文件引入到我们的项目中就可以使用了,当然还得引入protobuf的依赖包。

1、我们需要到官网下载protobuf的相应版本,我这里下载的是windows下的3.1.0版protoc-3.1.0-win32.zip

2、将下载好的zip解压,能看到bin目录下有一个protoc.exe的文件,等下需要用它来编译文件,我们直接在bin目录下      创建一个简单的person.proto的描述文件,内容如下:

  1. syntax = "proto3";
  2. option java_package = "gudao.red.protobuf";
  3. option java_outer_classname = "PersonFactory";
  4. message Person{
  5. int32 id = 1;
  6. string name = 2;
  7. int32 age = 3;
  8. Addr addr = 4;
  9. }
  10. message Addr{
  11. string contry = 1;
  12. string city = 2;
  13. }

内容非常简单,大概介绍一下:

syntax = "proto3";   我们使用proto3版协议

option java_package = "gudao.red.protobuf"; 编译之后生成的Java文件的包名

option java_outer_classname = "PersonFactory"; 编译之后生成的Java类的类名

message 相当于Java中的class

详细的介绍,还请自行去官网查看

3、使用protoc编译上述.proto文件,生成Java类,使用如下命令完成该操作

  1. protoc --java_out=./src ./person.proto

--java_out:生成的Java文件输出的位置,其他语言有相应的选项

这样就会在src目录下生成一个 名为PersonFactory的Java文件

4、将PersonFactory.java文件引入到我们的项目中,并引入对应版本的protobuf的依赖包

5、写测试代码

  1. package gudao.red.protobuf_test;
  2. import java.net.Socket;
  3. import gudao.red.protobuf.PersonFactory.Addr;
  4. import gudao.red.protobuf.PersonFactory.Person;
  5. public class Client {
  6. public static void main(String[] args) throws Exception {
  7. Socket socket = new Socket("127.0.0.1",3030);
  8. Person.Builder person = Person.newBuilder();
  9. Addr.Builder addr = Addr.newBuilder();
  10. addr.setContry("china").setCity("shenzhen");
  11. person.setId(1).setAge(12).setName("ccf");
  12. person.setAddr(addr);
  13. byte[] messageBody = person.build().toByteArray();
  14. int headerLen = 1;
  15. byte[] message = new byte[headerLen+messageBody.length];
  16. message[0] = (byte)messageBody.length;
  17. System.arraycopy(messageBody, 0,  message, 1, messageBody.length);
  18. System.out.println("msg len:"+message.length);
  19. socket.getOutputStream().write(message);
  20. }
  21. }
  1. package gudao.red.protobuf_test;
  2. import java.net.ServerSocket;
  3. import java.net.Socket;
  4. import gudao.red.protobuf.PersonFactory.Person;
  5. public class Server {
  6. /**
  7. * @param args
  8. */
  9. public static void main(String[] args) throws Exception {
  10. // TODO Auto-generated method stub
  11. ServerSocket serverSock = new ServerSocket(3030);
  12. while(true){
  13. Socket sock = serverSock.accept();
  14. byte[] msg = new byte[256];
  15. sock.getInputStream().read(msg);
  16. int msgBodyLen = msg[0];
  17. System.out.println("msg body len:"+msgBodyLen);
  18. byte[] msgbody = new byte[msgBodyLen];
  19. System.arraycopy(msg, 1, msgbody, 0, msgBodyLen);
  20. Person person = Person.parseFrom(msgbody);
  21. System.out.println("Receive:");
  22. System.out.println(person);
  23. }
  24. }
  25. }

先后启动Server和Client,就可以看到控制台的输出如下:

至此,我们的简单使用过程就完成了,是不是很简单。是,这个例子看上去是挺简单的,但如果我们需要序列化的类非常多,那么我们是不是得写非常多的.proto文件,并且还需要更新它们,这个代价可以想象一下也是非常大的。那么,接下来我们就来讲一讲protostuff,看这名字是不是跟protobuf很像,嗯,它们是有关系,前者就是基于后者实现的。

6、protostuff是一个基于protobuf实现的序列化方法,它较于protobuf最明显的好处是,在几乎不损耗性能的情况下做到了不用我们写.proto文件来实现序列化。使用它也非常简单,所以直接上代码。

  1. package gudao.red.protostuff;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. public class Po {
  5. private Integer id;
  6. private String name;
  7. private String remark;
  8. private Integer age;
  9. private int[] array;
  10. private InnerPo innerPo;
  11. private List<String> more;
  12. public Po(){}
  13. public Po(Integer id,String name,String remark,Integer age,
  14. int[] array,InnerPo innerPo,List<String> more){
  15. this.id = id;
  16. this.name = name;
  17. this.remark = remark;
  18. this.age = age;
  19. this.array = array;
  20. this.innerPo = innerPo;
  21. this.more = more;
  22. }
  23. public Integer getId() {
  24. return id;
  25. }
  26. public void setId(Integer id) {
  27. this.id = id;
  28. }
  29. public String getName() {
  30. return name;
  31. }
  32. public void setName(String name) {
  33. this.name = name;
  34. }
  35. public String getRemark() {
  36. return remark;
  37. }
  38. public void setRemark(String remark) {
  39. this.remark = remark;
  40. }
  41. public Integer getAge() {
  42. return age;
  43. }
  44. public void setAge(Integer age) {
  45. this.age = age;
  46. }
  47. public int[] getArray() {
  48. return array;
  49. }
  50. public void setArray(int[] array) {
  51. this.array = array;
  52. }
  53. public InnerPo getInnerPo() {
  54. return innerPo;
  55. }
  56. public void setInnerPo(InnerPo innerPo) {
  57. this.innerPo = innerPo;
  58. }
  59. public List<String> getMore() {
  60. return more;
  61. }
  62. public void setMore(List<String> more) {
  63. this.more = more;
  64. }
  65. @Override
  66. public String toString() {
  67. StringBuffer sb = new StringBuffer();
  68. sb.append("id:"+id+"\n");
  69. sb.append("name:"+name+"\n");
  70. sb.append("remark:"+remark+"\n");
  71. sb.append("age:"+age+"\n");
  72. sb.append("array:"+Arrays.toString(array)+"\n");
  73. sb.append("innerPo:"+innerPo.toString()+"\n");
  74. sb.append("more:"+more);
  75. return  sb.toString();
  76. }
  77. }
  78. class InnerPo{
  79. private Integer id;
  80. private String name;
  81. public InnerPo(){}
  82. public InnerPo(Integer id,String name){
  83. this.id = id;
  84. this.name = name;
  85. }
  86. public Integer getId() {
  87. return id;
  88. }
  89. public void setId(Integer id) {
  90. this.id = id;
  91. }
  92. public String getName() {
  93. return name;
  94. }
  95. public void setName(String name) {
  96. this.name = name;
  97. }
  98. @Override
  99. public String toString() {
  100. return id+"-"+name;
  101. }
  102. }
  1. package gudao.red.protostuff;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import com.dyuproject.protostuff.LinkedBuffer;
  5. import com.dyuproject.protostuff.ProtostuffIOUtil;
  6. import com.dyuproject.protostuff.runtime.RuntimeSchema;
  7. public class ProtostuffTest {
  8. static RuntimeSchema<Po> poSchema = RuntimeSchema.createFrom(Po.class);
  9. private static byte[] decode(Po po){
  10. return ProtostuffIOUtil.toByteArray(po, poSchema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
  11. }
  12. private static Po ecode(byte[] bytes){
  13. Po po = poSchema.newMessage();
  14. ProtostuffIOUtil.mergeFrom(bytes, po, poSchema);
  15. return po;
  16. }
  17. public static void main(String[] args) {
  18. InnerPo innerPo = new InnerPo(1, "InnerPo1");
  19. List<String> list = new ArrayList<String>();
  20. list.add("a");
  21. list.add("b");
  22. Po po = new Po(1, "Fong", "备注", 24, new int[]{1,2,3,4},innerPo,list);
  23. byte[] bytes = decode(po);
  24. System.out.println(bytes.length);
  25. Po newPo = ecode(bytes);
  26. System.out.println(newPo);
  27. }
  28. }

protobuf和protostuff的区别的更多相关文章

  1. java序列化/反序列化之xstream、protobuf、protostuff 的比较与使用例子

    目录 背景 测试 环境 工具 说明 结果 结论 xstream简单教程 准备 代码 protobuf简单教程 快速入门 下载.exe编译器 编写.proto文件 利用编译器编译.proto文件生成ja ...

  2. protostuff简单应用

    protobuf是谷歌推出的与语言无关.平台无关的通信协议,一个对象经过protobuf序列化后将变成二进制格式的数据,所以他可读性差,但换来的是占用空间小,速度快.居网友测试,它的序列化效率是xml ...

  3. 通讯协议序列化解读(二) protostuff详解教程

    上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html  前言:上一面文章我们介绍了java序列化,以及谷歌protobu ...

  4. Protostuff序列化分析

    前言最近项目中需要将业务对象直接序列化,然后存数据库:考虑到序列化.反序列化的时间以及生产文件的大小觉得Protobuf是一个很好的选择,但是Protobuf有的问题就是需要有一个.proto的描述文 ...

  5. Protostuff具体解释

    Protostuff具体解释 作者:chszs,未经博主同意不得转载. 经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 一.Protostuff介绍 Proto ...

  6. Protobuf 小试牛刀

    本文以PHP为例. 环境: CentOS 6.8 proto 3.8 PHP 7.1.12 PHP protobuf扩展 3.8.0 go1.12.5 linux/amd64 本文示例仓库地址: ht ...

  7. Protobuf的上手使用

    这里不赘述Json和Protobuf的比较和区别,只谈谈简单的使用 1.在Client-Server交互的过程中,都是以二进制数据传输,所以Json和Protobuf在使用的过程中,都存在序列化和反序 ...

  8. protobuf 协议浅析

    目录 Protobuf 协议浅析 1. Protobuf 介绍 1.1 Protobuf 基本概念 1.2 Protobuf 的优点 1.3 Protobuf, JSON, XML 的区别 2. Pr ...

  9. kafka消费者客户端

    Kafka消费者 1.1 消费者与消费者组 消费者与消费者组之间的关系 ​ 每一个消费者都隶属于某一个消费者组,一个消费者组可以包含一个或多个消费者,每一条消息只会被消费者组中的某一个消费者所消费.不 ...

随机推荐

  1. poj 1182 (关系并查集) 食物链

    题目传送门:http://poj.org/problem?id=1182 这是一道关系型并查集的题,对于每个动物来说,只有三种情况:同类,吃与被吃: 所以可以用0,1,2三个数字代表三种情况,在使用并 ...

  2. 如何搭建http服务仓库

    1.拷贝仓库repo-A文件到服务器/media/D: 2.通过createrepo_c 生成仓库rpm信息数据 cd repo-A createrepo . 3.chmod -R 775  repo ...

  3. PS合成的5个要点:场景、对比、氛围、模糊、纹理

    是否觉得做合成打开PS之后无处下手,做完之后总觉得缺少故事情节?这一次分享的5个要点,是个人觉得需要重视的,每一点都有一个案例来让作品变得多一份惊喜.(申明:文中素材均来自网络,这里仅作分享交流作用) ...

  4. [Robot Framework] 学习资料

    https://www.cnblogs.com/pachongshangdexuebi/category/981644.html Robot Framework学习笔记(一)------环境搭建 Ro ...

  5. Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用

    Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/101174 ...

  6. eclipse项目两个红点

    Description Resource Path Location Type Unbound classpath container: 'JRE Sy 选中项目右键build path 选择libr ...

  7. js中的find(),filter(),has()的用法和区别

    filter():操作当前元素集,删除不匹配的元素,得到一个新的集合 <ul> <li class="a">list item 1</li> & ...

  8. jquery查找frameset框架内iframe的元素

    老系统还幸存有过时的frameset框架,维护升级工作需要对其内部的iframe中的元素进行相关操作.使用jquery查找子iframe页面内的元素时,总找不到目标元素.后来发现少了contents ...

  9. vs2008 安装部署 启动项

    具体操作办法如下: 鼠标右键安装项目->视图->注册表 依次创建键: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion ...

  10. Android NDK定位.so文件crash代码位置

    参考:http://blog.csdn.net/xyang81/article/details/42319789 问题:      QRD8926_110202平台的Browser必现报错.(去年的项 ...