我想使用protobuf代替Json在消息队列之间进行通信。
我知道在只有一条原型信息时如何处理它。
假设proto文件是:
//person.proto
syntax = "proto3";
option java_outer_classname = "PersonProto";
message Person {
int32 id = 2;
string name = 1;
string email = 3;
}
现在,我可以用以下方法处理它:
PersonProto.Person person = PersonProto.Person.newBuilder()
.setEmail("123@test.com")
.setId(1)
.setName("name-test")
.build();
byte[] bytes = person.toByteArray();
//Transfer from publisher to consumer between message queue.
//I can deserialise it, because i know the proto message is Person.
PersonProto.Person.parseFrom(bytes);
但是如果有多条原型消息怎么办?
假设有另一个名为Address
的原型消息。
syntax = "proto3";
option java_outer_classname = "PersonProto";
message Person {
int32 id = 2;
string name = 1;
string email = 3;
}
message Address {
string address = 1;
}
当消费者从消息队列接收到字节数组时,如何知道它是哪个原型消息?以及如何反序列化字节数组?
答案 0 :(得分:4)
Protobuf 3引入了Any的概念,其作用方式与@AdamCozzette解释的顶级消息模式类似。
在写入方,您将邮件打包在Any:
中Any any = Any.parseFrom(in);
if (any.is(Person.class)
{
Person person = any.unpack(Person.class);
...
}
else if (any.is(Address.class);
{
Address address = any.unpack(Address.class);
...
}
else
{
//Handle unknown message
}
然后在阅读端阅读Any并打开您感兴趣的类型:
dat1 = data.frame(a = c(0.1,0.2,0.3,0.4,0.5), b = c(0.6,0.7,0.8,0.9,0.10), c = c(0.12,0.13,0.14,0.15,0.16), d = c(NA, NA, NA, NA, 0.5))
a b c d
1 0.1 0.6 0.12 NA
2 0.2 0.7 0.13 NA
3 0.3 0.8 0.14 NA
4 0.4 0.9 0.15 NA
5 0.5 0.1 0.16 0.5
使用Any不需要特殊的消息类型( top-level-message ),但也会删除类型安全元素,因为您可能会收到消息消费代码不知道如何处理。
答案 1 :(得分:2)
协议缓冲区不是自描述的,因此通常当您获得序列化的protobuf时,无法在不知道期望的模式的情况下解释其内容。
在您的情况下,我建议使用oneof
字段。您可以为队列消息设置一个顶级消息类型,并使其包含一个包含Person或Address的oneof
字段:
message TopLevelMessage {
oneof inner_message {
Person person = 1;
Address address = 2;
}
}
消费代码需要这样的switch语句才能检索内部消息:
TopLevelMessage topLevelMessage = TopLevelMessage.parseFrom(...);
switch (topLevelMessage.getInnerMessageCase())
{
case PERSON:
Person person = topLevelMessage.getPerson();
...
break;
case ADDRESS:
Address address = topLevelMessage.getAddress();
...
break;
default:
...
}