在我们的开发过程中,序列化是经常需要处理的问题,比如在做分布式访问数据时,或者是在做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. HTTP.ContentType

    1. multipart/x-mixed-replace http://blog.dubbelboer.com/2012/01/08/x-mixed-replace.html

  2. 部分开源gis 方案的比较

    3.1MapServer和GeoServer的总体对比 功能上:MapServer弱于GeoServer,QGIS要强于UDIG. 效率上:Mapserver对WMS(Web Map service) ...

  3. 201621123008 《Java程序设计》第12周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 面向系统综合设计-图书馆管理系统或购物车 使用流与文件改造你的图书馆管理系统或购物车. 2.1 简述如何 ...

  4. hook 9大类

    HOOK技术主要分为两大类,一是内核层HOOK,一是用户层HOOK. 用户层HOOK也就是在ring3环境下hook kenerl32.dll.User3.dll.Gui32.dll.Advapi.d ...

  5. Python的程序入口 __name__属性

    python中每个模块都有一个 '__name__' 属性,当其值为 '__main__' 时,表名该模块自身在运行,否则是被引入的. 当一个模块被当做一个整体调用的时候,模块名.__name__ 的 ...

  6. String类为什么设计成不可变的

    在Java中将String设计成不可变的是综合考虑到各种因素的结果,需要综合考虑内存.同步.数据结构以安全方面的考虑. String被设计成不可变的主要目的是为了安全和高效. 1)字符串常量池的需要 ...

  7. autohotkey快捷键

    ;已经基本修复了输入带shift的时候跟输入法中英文切换之间的冲突 SetStoreCapslockMode, off SetKeyDelay, ^CapsLock:: #UseHook ;用这个和下 ...

  8. openssl编译安装-各种蛋疼

    arm平台  ubuntu Linux xxxxxx 3.0.62 #2 PREEMPT Tue Apr 2 20:14:12 CST 2013 armv7l armv7l armv7l GNU/Li ...

  9. MathExam

    MathExam 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 575 605 • Est ...

  10. js文件中获取${pageContext.request.contextPath}

    一般从 JSP文件中,可以直接使用 ${pageContext.request.contextPath}非常方便的获得当前页面的路径,用来处理被 Apache2代理之后出现 URL变化的问题,比如增加 ...