如何最好地指定与Netty一起使用的Protobuf(最好使用内置的protobuf支持)

lah*_*her 6 java protocol-buffers netty

我在协议缓冲区中指定协议.传输层正在利用Netty的Protocol Buffers支持 - 重要的是Netty的ProtobufDecoder接受一种且只有一种类型的MessageLite.

现在,我想在此频道下发送各种不同的消息类型,每个子类型都有与之关联的结构化信息.协议缓冲区没有继承机制,所以我使用的是一种组合.我不确定我是否正确的方式.

我的方法是使用枚举对我的不同事件进行分类,并使用可选成员封装它们的差异.请参阅.proto下面的内容,为了清楚起见,我对其进行了简化.

我的问题是接收代码需要在EventType.ERROR和ErrorEventDetail之间建立关联.这只是感觉有点笨拙.

简化Events.proto:

package events;

option java_package = "com.example";
option java_outer_classname = "EventProtocol";

message Event {
  enum EventType {
    START = 0;
    DELEGATE = 1;
    ERROR = 2;
    STOP = 3;
  }
  required events.Event.EventType event_type = 1 [default = START];
  required int32 id = 2;
  required int64 when = 3;
  optional StartEventDetail start_event_detail = 4;
  optional DelegateEventDetail delegate_event_detail = 5;
  optional ErrorEventDetail error_event_detail = 6;
  optional StopEventDetail stop_event_detail = 7;
}

message StartEventDetail {
    required string object_name = 1;
}

message DelegateEventDetail {
    required int32 object_id = 2;
    required string task = 3;
}

message ErrorEventDetail {
  required string text = 1;
  required int32 error_code = 2;
  optional Event cause = 3;
}

message StopEventDetail {
    required int32 object_id = 2;
}
Run Code Online (Sandbox Code Playgroud)

这是最佳的吗?我会不会以某种方式使用扩展,或者可能还有其他一些用途enum

或者,我是否应该创建一个全新的OneToOneDecoder,它可以通过某种标头识别消息类型?我能做到这一点,但我宁愿不......

谢谢

tol*_*ius 6

看起来你已经非常接近/已经使用了一种称为联盟类型的Google的protobufs技术

要点是你有一个专门的type领域,你可以"切换"以了解要获得的消息:

message OneMessage {
  enum Type { FOO = 1; BAR = 2; BAZ = 3; }

  // Identifies which field is filled in.
  required Type type = 1;

  // One of the following will be filled in.
  optional Foo foo = 2;
  optional Bar bar = 3;
  optional Baz baz = 4;
}
Run Code Online (Sandbox Code Playgroud)

其中Foo,Bar和Baz可以在其他文件中定义为单独的消息.你可以打开类型来获得实际的有效载荷(它是Scala,但你可以用Java做同样的事情switch):

OneMessage.getType match { 

  case OneMessage.Type.FOO => 

    val foo = OneMessage.getFoo
    // do the processing
    true

  case OneMessage.Type.BAR => 

    val bar = OneMessage.getBar
    // do the processing
    true

  case OneMessage.Type.BAZ => 

    val baz = OneMessage.getBaz
    // do the processing
    true

}
Run Code Online (Sandbox Code Playgroud)