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

    Java请求:就是用来对java项目的类进行压测 例子:将输入的两个参数通过IO存入文件 1.创建Java工程,工程目录如下 2.将Jmeter-lib下面的所有jar包导入java工程, 3.创建一 ...

  2. Windows服务安装、卸载、启动和关闭的管理器

    最近在重构公司的系统,把一些需要独立执行.并不需要人为关注的组件转换为Windows服务,Windows服务在使用的过程中有很多好处,相信这一点,就不用我多说了.但是每次都要建立Windows服务项目 ...

  3. 故障处理分析:华为5885v3 cable/ Interconnect (LEFT Panel)

    故障现象: 处理结果: 1.重新把插左前面板,重启,故障消失.

  4. 去掉easyui datagrid内部虚线的方式。

    去掉easyui        datagrid内部虚线的方式.easyui datagrid的样式是统一写在样式文件中的,如果想要统一替换可以找对应的datagird样式文件中的以下部分.如果想要改 ...

  5. poj 2777(线段树+lazy思想) 小小粉刷匠

    http://poj.org/problem?id=2777 题目大意 涂颜色,输入长度,颜色总数,涂颜色次数,初始颜色都为1,然后当输入为C的时候将x到y涂为颜色z,输入为Q的时候输出x到y的颜色总 ...

  6. dpdk优化相关 转

    注:本文是参照了一些其他文章,原文地址点击这里. 首先根据这篇文章进行了性能瓶颈的分析 策略与方法 首先根据木桶原理,首先要找到最弱的地方,怎么找往上看↑. 想能优化需要考虑如下: 优化BIOS设置 ...

  7. 接口没添加@responseBody注解

    今天在重写springaop小demo时,发现调用接口时,可以在控制台上正常返回结果,但是页面报错,debug半天,可以看到是调用了modelview的时候出错,找不到视图了.. debug的时候控制 ...

  8. centos7构建python2.7常用开发环境

    把下面的代码保存到一个sh文件中执行即可 yum -y install epel-release yum -y install python-pip yum -y install mysql-deve ...

  9. Git及其二次开发

    Git And TFS: 将 Visual Studio 用于 Git:http://msdn.microsoft.com/zh-cn/library/hh850437.aspx TFVC 和 Git ...

  10. mybatis 为什么要设置jdbcType

    转载自:http://makemyownlife.iteye.com/blog/1610021 前天遇到一个问题 异常显示如下: 引用 Exception in thread "main&q ...