分享

Protobuf3 系列一 第一个Java demo

 WindySky 2017-08-01

概念

Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler

简单的说, Protobuf3是类似json,xml的数据交换协议,但是它比它们传输的数据更小,传输的速度更快; 跨语言交互,支持大部分主流编程语言

Demo

Message

Protobuf3通过proto文件定义交互的对象,基本的数据结构叫做Message。 以下是本次使用的第一个demo

// 如果使用此注释,则使用proto3; 否则使用proto2
syntax = "proto3";
// 生成类的包名
option java_package = "com.hry.spring.proto.simple";
//生成的数据访问类的类名,如果没有指定此值,则生成的类名为proto文件名的驼峰命名方法
option java_outer_classname = "FirstDemo";
message Demo {  
  int32 id = 1;  
  string name = 2;
  string email = 3;
  repeated int32 mylist = 4; // List列表
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

repeated : 在Java中表示这是一个List列表
int32, string 分别对应java中的int, String

生成Java类

定义后proto,则可以通过官方的工具生成类 protoc-3.0.0-win32.zip

有两种方式生成java类

方法一通过cmd命令:
protoc参数的意义见下方的ProtoGenerateClass 类注释

D:/tool/protoc/protoc-3.0.0-win32/bin/protoc.exe -I=D:/project/git/spring_boot/protobuf --java_out=d:/tmp D:/project/git\spring_boot/protobuf/src/main/resources/com/hry/spring/proto/simple/*.proto
  • 1
  • 1

方法二通过Java类来实现
封装调用window命令的类

public class Cmd {
    private void writeInputStream2OutputStream(InputStream in, OutputStream out) throws IOException {
        LineNumberReader lnr = new LineNumberReader(new InputStreamReader(in, "UTF-8"));
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, "UTF-8"));
        String s;
        while ((s = lnr.readLine()) != null) {
            // 打印信息
            pw.println(s);
        }
        // 关闭输出流
        lnr.close();
        pw.close();
    }

    public void execute(List<String> commandList){
        Assert.notNull(commandList, "commandList can't be null!");
        // 如:protoc.exe -I=D:/project/git/spring_boot/protobuf --java_out=d:/tmp D:/project/git\spring_boot/protobuf/src/main/resources/com/hry/spring/proto/simple/person-entity.proto
        ProcessBuilder pb = new ProcessBuilder(commandList);
        // 错误流和输出流合并到一起输出,否则可能因为2个流的某个缓存区满了而导致现场阻塞
        //错误和正确信息合并输出,因为输出有2个,一个是正确,一个错误,着个只要其中有1个无法被实时读取,则可能造成进程阻塞
        pb.redirectErrorStream(true);
        Process p;
        try {
            p = pb.start();
            writeInputStream2OutputStream(p.getInputStream(), System.err);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        int iResult = p.exitValue();
        if(iResult == 0){
            System.out.println(" result = " +p.exitValue() + " execute command success! Command = " + commandList);

        }else{
            System.out.println(" result = " +p.exitValue() + " execute command failure! Command = " + commandList);
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

调用cmd类

public class ProtoGenerateClass {
    // protoc的目录
    private static final String PROTOC_FILE = "D:/tool/protoc/protoc-3.0.0-win32/bin/protoc.exe";
    // specifies a directory in which to look for .proto files when resolving import directives
    private static final String IMPOR_TPROTO = "D:/project/git/spring_boot/protobuf";
    // 生成java类输出目录
    private static final String JAVA_OUT = "d:/tmp";
    // 指定proto文件
    private static final String protos = "D:/project/git/spring_boot/protobuf/src/main/resources/com/hry/spring/proto/simple/*.proto";

    public static void main(String[] args) throws IOException {
        List<String> lCommand = new ArrayList<String>();
        lCommand.add(PROTOC_FILE);
        lCommand.add("-I=" + IMPOR_TPROTO );
        lCommand.add("--java_out=" + JAVA_OUT);
        lCommand.add(protos);

        Cmd cmd = new Cmd();
        cmd.execute(lCommand);
    }   

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

调用Java类

调用上面的方法生FirstDemo类后,由于此类过大,这里不列出,只显示如何调用此类:

public class FirstDemoTest {

    @Test
    public void testMyPerson() throws InvalidProtocolBufferException{
         //模拟将对象转成byte[],方便传输
        FirstDemo.Demo.Builder builder = Demo.newBuilder();
        builder.setId(1);
        builder.setName("name");
        builder.setEmail("hryou0922@126.com");
        Demo person = builder.build();
        System.out.println("before :"+ person.toString());

        System.out.println("===========Person Byte==========");
        for(byte b : person.toByteArray()){
            System.out.print(b);
        }
        System.out.println();
        System.out.println(person.toByteString());
        System.out.println("================================");

        //模拟接收Byte[],反序列化成Person类
        byte[] byteArray =person.toByteArray();
        MyPerson p2 = MyPerson.parseFrom(byteArray);
        System.out.println("after :" +p2.toString());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

打印内容

before :id: 1
name: "name"
email: "hryou0922@126.com"

===========Person Byte==========
8118411097109101261710411412111111748575050644950544699111109
<ByteString@73035e27 size=27>
================================
after :id: 1
name: "name"
email: "hryou0922@126.com"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

代码

github代码

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多