记录:Protocol Buffers(protobuf)在Java开发中使用

数据交换的方式很多比如:XML,JSON,Protobuf。虽然protobuf很流行,并且系出名门,可是没怎么用过。通过阅读google developers里关于protocal-buffers的内容基本可以使用它了。如果你访问该链接https://developers.google.com/protocol-buffers/ 失败的话,肯能需要VPN服务。

语言手册:https://developers.google.com/protocol-buffers/docs/proto

Protobuf-Java:https://developers.google.com/protocol-buffers/docs/javatutorial

下载地址:https://developers.google.com/protocol-buffers/docs/downloads

如果是Windows系统建议下载protoc-2.6.0-win32.zip,这样即可省去编译。

官方提供的C++,Python,Java的运行库下载:https://code.google.com/p/protobuf/downloads/list 这里需要注意的是运行库的版本需要和protoc的版本对应。

下文是通过使用protocal-buffers官网提供的一个数据格式的例子来熟悉protocal buffer在Java开发中的基本使用方法。

1.编写一个.proto文件命名为:addressbook.proto,该文件内容来自protocal-buffers官网

package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

2.使用protoc-2.6.0-win32.zip解压后的protoc.exe生成Java类

查询protoc.exe帮助:

D:\__dev\jar\protobuff>protoc.exe -h

生成Java类:

D:\__dev\jar\protobuff>protoc.exe --proto_path=F:\__eclipse\test\proto 
--java_out=F:\__eclipse\test\src F:\__eclipse\test\proto\addressbook.proto

在Eclipse中的项目目录结构图如下:

说明:

上图中:addressbook.proto数据格式文件,AddressBookProtos.java是生成的java类,protobuf-java-2.5.0.jar是Java运行时类库。

3.使用AddressBookProtos类来实现对象的序列号和反序列化,了解Protocol-buffers jar的相关API

代码实例:

package com.example.test;

import java.util.Arrays;

import com.example.tutorial.AddressBookProtos.AddressBook;
import com.example.tutorial.AddressBookProtos.Person;
import com.google.protobuf.InvalidProtocolBufferException;

public class AddressBookProtoUse {

    public static void main(String[] args) {
        //构建一个Person对象
        Person person = Person
                .newBuilder()
                .setEmail("[email protected]")
                .setId(10086)
                .setName("zhangsan")
                .addPhone(
                        Person.PhoneNumber.newBuilder().setNumber("186")
                                .setType(Person.PhoneType.HOME).build())
                .build();
        System.out.println("打印输出Person对象信息:");
        System.out.println(person);
        System.out.println("Person对象调用toString()方法:");
        System.out.println(person.toString());

        System.out.println("Person对象字段是否初始化:" + person.isInitialized());

        // 序列号
        System.out.println("Person对象调用toByteString()方法:");
        System.out.println(person.toByteString());

        System.out.println("Person对象调用toByteArray()方法:");
        System.out.println(Arrays.toString(person.toByteArray()));
        
        try {
            System.out.println("反序列化后的对象信息:");
            // 反序列化
            Person newPerson = Person.parseFrom(person.toByteArray());
            System.out.println(newPerson);
            newPerson = Person.parseFrom(person.toByteString());
            System.out.println(newPerson);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }

        // 向地址簿添加两条Person信息
        AddressBook.Builder books = AddressBook.newBuilder();
        books.addPerson(person);
        books.addPerson(Person.newBuilder(person).setEmail("[email protected]")
                .build());
        System.out.println("AddressBook对象信息:");
        System.out.println(books.build());

    }
}

运行结果:

打印输出Person对象信息:
name: "zhangsan"
id: 10086
email: "[email protected]"
phone {
  number: "186"
  type: HOME
}

Person对象调用toString()方法:
name: "zhangsan"
id: 10086
email: "[email protected]"
phone {
  number: "186"
  type: HOME
}

Person对象字段是否初始化:true
Person对象调用toByteString()方法:
<[email protected] size=40>
Person对象调用toByteArray()方法:
[10, 8, 122, 104, 97, 110, 103, 115, 97, 110, 16, -26, 78, 26, 16, 122, 104, 97, 110, 103, 115, 97, 110, 64, 49, 54, 51, 46, 99, 111, 109, 34, 7, 10, 3, 49, 56, 54, 16, 1]
反序列化后的对象信息:
name: "zhangsan"
id: 10086
email: "[email protected]"
phone {
  number: "186"
  type: HOME
}

name: "zhangsan"
id: 10086
email: "[email protected]"
phone {
  number: "186"
  type: HOME
}

AddressBook对象信息:
person {
  name: "zhangsan"
  id: 10086
  email: "[email protected]"
  phone {
    number: "186"
    type: HOME
  }
}
person {
  name: "zhangsan"
  id: 10086
  email: "[email protected]"
  phone {
    number: "186"
    type: HOME
  }
}

探究AddressBookProtos类:

a.构造Person对象,Person类继承自com.google.protobuf.GeneratedMessage类,而GeneratedMessage类继承自AbstractMessage类,并且实现了序列化接口Serializable。在AbstractMessage类中重写了toString()方法,具体内容如下:

@Override
  public final String toString() {
    return TextFormat.printToString(this);
  }

于是有了Person对象调用toString()方法后直接输出Person对象的文本内容。

b.toByteString()返回的ByteString是一个不可变的byte序列,由AbstractMessage类实现。toByteArray()返回byte[]。这两个方法都是对象进行序列化的方法。

c.isInitialized()判断对象的字段是否初始化,该方法与Person类的initFields()方法相关。

initFields()源代码:

private void initFields() {
      name_ = "";
      id_ = 0;
      email_ = "";
      phone_ = java.util.Collections.emptyList();
    }

initFields()方法的调用是在Person类的默认实力对象初始化之后调用的,在Person类的静态代码块中可以看到:

static {
      defaultInstance = new Person(true);
      defaultInstance.initFields();
    }

d.Person类提供了一系列的反序列化的重载方法用来讲数据反序列化为Person对象。

e.关于Person对象的Build

Person类中有一个Builder的内部类,该类用来构建Person对象,并且为Person对象添加数据。

public static final class Builder extends
        com.google.protobuf.GeneratedMessage.Builder<Builder>
       implements com.example.tutorial.AddressBookProtos.PersonOrBuilder

4.通过学习官网的实例,手绘一张Java使用protobuf的基本流程图

时间: 2024-10-06 22:02:24

记录:Protocol Buffers(protobuf)在Java开发中使用的相关文章

Protocol Buffers(protobuf)java初体验

由于项目需要所以简单的研究了下protobuf.我也是参照网上的博客,所以大部分内容我也就不重复造轮子了.首先protobuf介绍点击这里,使用介绍点击这里,使用demo看这里.我个人的第一个例子也是参照这个demo来的,不过其中我有遇到一些问题,所以揪出来说说,也就给自己做个笔记,方便查阅. 基本的东西相信大家也了解了,直接步入主题了: 1.限定修饰符介绍 required\optional\repeated,之前给定的博客已经有这个介绍了我也不多说,这里把一些小玩儿拿出来讲讲 ①.requi

Protocol Buffers(Protobuf)开发者指南---概览

Protocol Buffers(Protobuf)开发者指南---概览 欢迎来到protocol buffers的开发者指南文档,protocol buffers是一个与编程语言无关‘.系统平台无关.可扩展的结构化数据序列化/反序列化工具,适用于通讯协议,数据存储等场合. ps:为了方便拼写,下文的protobuf就是指protocol buffers. 本文档的面向读者是:希望使用protobuf的 Java.C++.Python的开发者.此概览将向您介绍如何开始使用protobuf,然后您

Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南

Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南 约定:为方便书写,ProtocolBuffers在下文中将已Protobuf代替. 本指南将向您描述如何使用protobuf定义i结构化Protobuf数据,包括.proto文件语法和如何使用.proto文件生成数据存取类. 作为一个参考指南,本文档将以示例的形式一步步向您介绍Protobuf的特点.您可以参考您所选择的语言的示例.tutorial ----------------------------

完整java开发中JDBC连接数据库代码和步骤

完整java开发中JDBC连接数据库代码和步骤 JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的静态方法forName(String  className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver") ; }catch(Class

java开发中的那些事(3)-------最常用到的几个快捷键

今天去看了韩寒的<后会无期>,感慨颇多. 这里记录下现在常会用到的几个快捷键,不多,却是当前最常用到: 1.ctrl+f  ----------------"搜索", 这个应该在大多数人来说都太简单了,可惜我也是知道不长时间: 2.ctrl+shift+r  --------"工程内搜索",这个也是搜索,不过是搜索整个工程的,这个知道后美滋滋了好久: 3.ctrl+/  ----------------"简单注释","//&

java开发中的那些事(6)------一次ajax调用中的问题

这个周末就要到这次开发任务的结尾了,不过也到这时候了,才发现用起来比较顺手了,前几次项目中也有过啊,说起来实实在在用过的才3个项目,就分别用了不同的,着实有些痛苦啊,初学阶段的jsp+servlet还算是初学,可这后面的loushang和ssh2是让我欢喜让我忧啊,高兴的是框架的魅力让我情不自禁,可这样的框架我啥时候才能自己组的那么完善,甚至现在用起来还磕磕绊绊的.总结下这次的大收获的话,一方面是这个框架,另一方面的话就是ajax和json了,这个在我来说是比较陌生的地方,虽然现在我可以用,但原

java开发中遇到的问题及解决方法(持续更新)

摘自 http://blog.csdn.net/pony12/article/details/38456261 java开发中遇到的问题及解决方法(持续更新) 工作中,以C/C++开发为主,难免与其他服务和Web进行交换,Java开发必不可少,又不想动用Eclipse大家伙,只能自己动手编写脚本进行Java代码的编译和运行,期间遇到的一些问题,记录下来供自己和大家参考.1)软件包不存在/软件包 javax.jms 不存在    这是由于javac编译时找不到javax.jms所在的软件包,因此将

java开发中的那些事(4)-------没完没了的time of error

今天心情有些郁闷啊,一个空指针折磨了一下午,到现在还没有解决,结果把高手找来也没弄了,还得继续自己琢磨,再一点点改一点点找吧,可是现在不想搞了,准备回家,白白浪费这一个多小时,在这之前把另一个同时在折磨自己的一个问题的解决给记录下,感觉还挺有用. 问题展示: 就这么个弹出框,改动MyEclipse文件后,无论保存还是修改,都在疯狂的弹出,没完没了的出现,一度让我抓狂啊. 问题原因: 不详 记得之前也出现过一次,是高手当时顺手就给解决了,这次也不知道为什么,想造这种情况还不知道如何下手:网上看到几

java开发中的那些事(5)--------一点经历,败给2分钟的2个小时

特意记下这个经历,这个让我感慨万千又斗志昂扬的一次经历,这是经验,也是生活. 故事的始末是这样的,先给大家上几句代码,现在身在家中,只能凭记忆敲打几行,大致意思倒不会错: {field:'code',align:'center'} {field:'btfid',align:'center',hidden:'true', formatter:function(value,row,rowIndex){ return "<a href="javascript:void(0)"