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

    函数原型作用域:作用范围为函数形参表范围,起始于“(”,结束于“)”,这是声明 定义是属于局部作用域,所以声明的时候不写形参名字也可以 类作用域:包含类体及在类外实现的本类成员函数的函数体 静态生存期 ...

  2. PAT乙级 解题目录

    有些题做得可能比较傻,有好方法,或者有错误还请告诉我,多多指教=.= 思路比较好的题目我都有讲的很详细. 剩下三道题有待优化,等改好了再上传.   标题 题目链接 解题链接 1001 害死人不偿命的( ...

  3. iOS.Book.Mac OS X and iOS Internals: To the Apple’s Core

    深入解析Mac OS X & iOS操作系统 http://product.china-pub.com/3769686

  4. Fedora : multilib version problems found

    摘自:https://smjrifle.net/fedora-fix-multilib-version-problems/ This error was due to duplicate packag ...

  5. HapMap

    HapMap五周年回顾 2011-01-12 | 作者: [关闭] 作者简介:曾长青,中国科学院北京基因组所研究员,博士生导师.CUSBEA奖学金.百人计划.杰出青年基金.首批新世纪百千万人才工程国家 ...

  6. iOS通过URL构建UIImage

    很多时候我们只能得到一个URL,然后需要构建一个UIImage. 通常情况下,我们一般都是通过SDWebImage来直接构建UIImageVIew的image,如何用URL直接构建UIImage呢? ...

  7. python提取百度经验<标题,发布时间,平均流量,总流量,具体的链接>

    之前想研究下怎么抓网页数据.然后就有了下面的练习了. 如有BUG.也纯属正常. 只是练习.请勿投入产品使用. #!/usr/bin/python # -*- coding: utf-8 -*- #Fi ...

  8. Codeforces 791B. Bear and Friendship Condition 联通快 完全图

    B. Bear and Friendship Condition time limit per test:1 second memory limit per test:256 megabytes in ...

  9. Eclipse创建Spring项目 未完

    使用的软件及版本 1)Eclipse:Eclipse Java EE IDE for Web Developers :Version: 2018-09 (4.9.0) 2)JDK:java versi ...

  10. Elastix GOIP 网关配合

    方案一 Gateway disallow=allallow=alaw&ulawcanreinvite=nodtmfmode=rfc2833host=192.168.1.108insecure= ...