文档格式

syntax =  "proto2";
package godme;

option java_package = "com.godme.protobuf";
option java_outer_classname = "Message";

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

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

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

    repeated PhoneNumber phones = 4;
}
message AddressBook{
    repeated Person person = 1;
}

版本( syntax)

syntax =  "proto2";

指定protoc编译版本。

名称空间(package)

package godme;

指定名称空间(namespace),为区别同名文件。

默认情况下,作为编译的java文件的包名。

参数

option java_package = "com.godme.protobuf";
option java_outer_classname = "Message";

java_package:指定编译的java文件的包名,不指定默认采用package指定的名称。

java_outer_classname:指定编译的java文件的类名,默认为Message

类型

type description
string 字符串
int32 int
int64 long
enum 枚举
other 其他复杂类型必须在proto文件内定义才能使用
可以通过import关键字导入其他proto文件定义的数据类型

修饰符

type description
required 必须,如果标记为required
当序列化或反序列化时该参数没有设置具体值,会抛出异常
optinoal 可选,序列化和反序列化时刻不必设置具体值
会根据类型自动设置默认值,也可以自己指定默认值
默认值下一个表进行说明
repeated 重复,单一类型的多个实例
相当于List,是指定对象的集合

默认值

type default
string "",空字符串
int32 0
int64 0
boolean false
optional PhoneType type = 2 [ default = HOME ];

通过[ default = value ]可指定默认值,记得修饰符要为optinoal

标记符

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

声明时=等号后面的,属于标记符,不是赋值操作。

使用15及一下的数字进行标记的字段,序列化是会使用更少的空间。

常用的关键属性尽量使用小数进行标记,以便于更快的序列或反序列化。

类管理

  • 定义

message关键字进行声明,然后用{}进行包括。

在内部依据前面的讲述,进行结构体的定义。

  • 结构

所有的message都定义在单个文件内部,message可以进行嵌套。

生成的java文件,类定义都在同一个java文件当中,是java_outer_classname的内部类。

至于嵌套的message,那就是内部类的内部类。

编译方式

protoc --proto_path=. --java_out=./../java message.proto
  • protoc:编译命令
  • --proto_path:指定proto文件的目录
  • --java_out:指定编译的java文件的路径
  • message.protoproto文件
    netty-protobuf基本

常用的就是这两个选项,根据语言的不同,还有:

option language
--cpp_out c++
--csharp_out c#
--js_out javascript
--objc_out Object-c
--php_out PHP
--python_out Python
--ruby_out Ruby

可以看到,protobuf支持的语言还是挺多的。

而且,添加多个out,可以一次性编译出多个语言的Class文件哦。

使用办法

编译成的java文件,会报错,需要protobuf-java这个jar包的支持。

compile(
            'io.netty:netty-all:4.1.10.Final',
            'com.google.protobuf:protobuf-java:3.6.1',
            'com.google.protobuf:protobuf-java-util:3.6.1'
    )
  • Builder
public class Main {
    public static void main(String[] args) {
        Message.Person.Builder builder = Message.Person.newBuilder();
        if(!builder.hasId()){
            builder.setId(1);
        }
        if(!builder.hasName()){
            builder.setName("godme");
        }
        if(!builder.hasEmail()){
            builder.setEmail("[email protected]");
        }
        Message.Person godme = builder.build();
    }
}

proto采用构造器模式,每次创建对象,都只能build出来。

builder只有两个方法

  • hasAttr:判断属性是否被设置(默认值)
  • setAttr:设置对应属性

如果是已有对象的其他模式,可以通过parseFrom进行反序列化,支持

  • String
  • Buffer
  • byteArray

更多类型参看API

  • Object
Message.Person person = builder.build();
Integer id = person.getId();
String name = person.getName();
String email = person.getEmail();
person.toBuilder();
person.toByteArray();
person.toByteString();

对象的方法,就是getAttrtoSomething

  • getAttr:获取属性
  • toSomething:序列化操作

简单操作

  • code
public class Main {
    public static void main(String[] args) throws IOException {
        Message.Person person = Message.Person.newBuilder()
                .setId(1)
                .setName("godme")
                .setEmail("[email protected]")
                .build();
        System.out.println(person.toString());
        String fileName = "person";
        writeToFile(person, fileName);
        Message.Person person2 = readFromFile(fileName);
        System.out.println(person2);
        System.out.println(person.equals(person2));
    }
    public static void writeToFile(Message.Person person, String fileName) throws IOException {
        FileOutputStream outputStream = new FileOutputStream(fileName);
        person.writeTo(outputStream);
        outputStream.flush();
        outputStream.close();
    }
    public static Message.Person readFromFile(String fileName) throws IOException {
        FileInputStream fileInputStream = new FileInputStream(fileName);
        Message.Person person = Message.Person.parseFrom(fileInputStream);
        return person;
    }
}
  • result
    netty-protobuf基本

小结

嗯,就是这样。

机器之间呢,就是通过流传输,就是要序列化/反序列化。

用这种东西,你可以把一个对象就这样传输到另一个机器上哦。

当然,必须是socket的流了,其他的也行。

代码在此

相关文章: