Netty学习——Google Protobuf的初步了解
学习参考的官网: https://developers.google.com/protocol-buffers/docs/javatutorial
简单指南详解:这个文档写的简直是太详细了。
本篇从下面三个步骤进行介绍:
详细内容,我就不做过多解释,自行查阅官方文档,在这只是记录,我觉得比较重要的东西,能够帮助我更好的理解。
I.Define message formats in a .proto file.
syntax = "proto2"; package tutorial; //包名 option java_package = "com.example.tutorial"; //针对于java的包名 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]; // optional类型 和定义默认值 } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; //repeated类型,其实就相当于java的ArrayList,用来 }
其他需要注意的点:
1.对于前两个字段java_package 和 package ,就是说,可以不写java_package,会默认 调用package ,写了java_package,java就会识别这个,但是就算写了java_package,也要package ,是为了其他语言能够有包名能够使用
2.这个数字,=1, =2 ,不是顺序,或者是赋值,只是每一个字段在Proto文件中,都会有一个唯一数字标识符
3.对于以下的三种类型 required,optional,repeated 官方推荐,尽量不是用required,因为弊大于利。
II. Use the protocol buffer compiler.
需要注意的地方:
使用PB编译器生成出的对象是不可变的,需要使用构建器的方法连模式(set.set.set )一个一个的去设置值,然后再需要最后使用build方法去完成整个对象的创建,如下介绍
每一次set完之后的返回结果,都是另一个构建器,就是为了能够在一行代码上,完成对象的构建
通过构建器的方法连模式,完成一个对象的创建和设置值的标准写法:如下
Person john = Person.newBuilder() .setId(1234) .setName("John Doe") .setEmail("") .addPhones( Person.PhoneNumber.newBuilder() .setNumber("555-4321") .setType(Person.PhoneType.HOME)) .build();
Message除了自定义的属性之外,还提供的有几个默认的方法,让你能够检查和操作整个消息
isInitialized()://检查是否所有的必备字段,都已经被设置值 toString(): //返回一个人类可读的字符形式,通常用于调试 mergeFrom()://(只有构建器才有)将另一个消息的内容,合并到当前消息当中并且覆盖之前的标量字段,合并复核的字段和重复的阻断,完成对象的合并 clear()://(只有构建器才有) 恢复到原来属性都为空的这个状态
解析和序列化这些消息
byte[] toByteArray(); //将消息序列化,并返回了包含原生字节的一个字节数组,就是把消息本身转换成字节数组 static Person parseFrom(byte[] data);//从给定的字节数组当中解析这条消息,将字节数组的内容转换成对象 void writeTo(OutputStream output);//将消息序列化,并输出到一个输出流当中, static Person parseFrom(InputStream input); //接着读取输入流中的消息并进行解析
注意:不能通过继承的方式,给这个对象添加更多的行为。
如果想要给这个message对象赋予响应的方法,可以借助使用多个message合并的方式来实现功能而并不是通过继承的方式
III. Use the Java protocol buffer API to write and read messages.
Writer a Message
import com.example.tutorial.AddressBookProtos.AddressBook; import com.example.tutorial.AddressBookProtos.Person; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; class AddPerson { // This function fills in a Person message based on user input. static Person PromptForAddress(BufferedReader stdin, PrintStream stdout) throws IOException { Person.Builder person = Person.newBuilder(); stdout.print("Enter person ID: "); person.setId(Integer.valueOf(stdin.readLine())); stdout.print("Enter name: "); person.setName(stdin.readLine()); stdout.print("Enter email address (blank for none): "); String email = stdin.readLine(); if (email.length() > 0) { person.setEmail(email); } while (true) { stdout.print("Enter a phone number (or leave blank to finish): "); String number = stdin.readLine(); if (number.length() == 0) { break; } Person.PhoneNumber.Builder phoneNumber = Person.PhoneNumber.newBuilder().setNumber(number); stdout.print("Is this a mobile, home, or work phone? "); String type = stdin.readLine(); if (type.equals("mobile")) { phoneNumber.setType(Person.PhoneType.MOBILE); } else if (type.equals("home")) { phoneNumber.setType(Person.PhoneType.HOME); } else if (type.equals("work")) { phoneNumber.setType(Person.PhoneType.WORK); } else { stdout.println("Unknown phone type. Using default."); } person.addPhones(phoneNumber); } return person.build(); } // Main function: Reads the entire address book from a file, // adds one person based on user input, then writes it back out to the same // file. public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE"); System.exit(-1); } AddressBook.Builder addressBook = AddressBook.newBuilder(); // Read the existing address book. try { addressBook.mergeFrom(new FileInputStream(args[0])); } catch (FileNotFoundException e) { System.out.println(args[0] + ": File not found. Creating a new file."); } // Add an address. addressBook.addPerson( PromptForAddress(new BufferedReader(new InputStreamReader(System.in)), System.out)); // Write the new address book back to disk. FileOutputStream output = new FileOutputStream(args[0]); addressBook.build().writeTo(output); output.close(); } }
Reader a Message
import com.example.tutorial.AddressBookProtos.AddressBook; import com.example.tutorial.AddressBookProtos.Person; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintStream; class ListPeople { // Iterates though all people in the AddressBook and prints info about them. static void Print(AddressBook addressBook) { for (Person person: addressBook.getPeopleList()) { System.out.println("Person ID: " + person.getId()); System.out.println(" Name: " + person.getName()); if (person.hasEmail()) { System.out.println(" E-mail address: " + person.getEmail()); } for (Person.PhoneNumber phoneNumber : person.getPhonesList()) { switch (phoneNumber.getType()) { case MOBILE: System.out.print(" Mobile phone #: "); break; case HOME: System.out.print(" Home phone #: "); break; case WORK: System.out.print(" Work phone #: "); break; } System.out.println(phoneNumber.getNumber()); } } } // Main function: Reads the entire address book from a file and prints all // the information inside. public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE"); System.exit(-1); } // Read the existing address book. AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(args[0])); Print(addressBook); } }