Ein Kollege von mir kam mit der Idee, Protokollpufferklassen zur Laufzeit zu erzeugen. Bedeutung:
Die Idee ist, dass der Server die Definition des Protokollpuffers als Teil des ersten Handshakes sendet und die Java-Anwendung die Klasse zur Laufzeit generiert und sie für die Kommunikation mit dem Server verwendet.
Ich frage mich, ob das überhaupt eine wichtige Idee ist und ob es möglicherweise einen Nutzen für einen solchen Anwendungsfall gibt.
Danke
Was Sie beschreiben, wird tatsächlich bereits von den Protocol Buffers-Implementierungen in C ++ und Java unterstützt. Sie müssen lediglich ein FileDescriptorSet
(wie in google/protobuf/descriptor.proto
), die FileDescriptorProto
s für jede relevante .proto
-Datei enthalten, dann DynamicMessage
, um die Nachrichten am empfangenden Ende zu interpretieren.
Um ein FileDescriptorProto
in C ++ zu erhalten, geben Sie den Nachrichtentyp Foo
, der in dieser Datei definiert ist, wie folgt vor:
Legen Sie alle FileDescriptorProto
s, die die benötigten Typen definieren, sowie alle importierten Dateien in ein FileDescriptorSet
proto. Beachten Sie, dass Sie google::protobuf::FileDescriptor
(das zurückgegebene Objekt) verwenden können by Foo::descriptor().file()
), um über Abhängigkeiten zu iterieren anstatt sie explizit zu benennen.
Senden Sie nun FileDescriptorSet
an den Client.
Verwenden Sie auf dem Client FileDescriptor.buildFrom()
konvertieren jedes FileDescriptorProto
auf einen Live- Descriptors.FileDescriptor
. Sie müssen sicherstellen, dass Abhängigkeiten vor Abhängigkeiten erstellt werden, da Sie die bereits erstellten Abhängigkeiten zu buildFrom()
wenn die Unterhaltsberechtigten zu bauen.
Von dort können Sie die FileDescriptor
findMessageTypeByName()
, um die Descriptor
Schließlich können Sie rufen Sie DynamicMessage.newBuilder(descriptor)
, um eine neue Builder-Instanz für den betreffenden Typ zu erstellen. DynamicMessage.Builder
implementiert die Message.Builder
Schnittstelle, die Felder wie getField()
und < a href="https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Message.Builder#setField(com.google.protobuf.Descriptors.FieldDescriptor,%20java.lang .Object) "> setField()
, um die Felder der Nachricht dynamisch zu bearbeiten (durch Angabe der entsprechenden FieldDescriptor
s).
Sie können auch DynamicMessage.parseFrom(descriptor,input)
um die vom Server empfangenen Nachrichten zu analysieren.
Beachten Sie, dass ein Nachteil von DynamicMessage
ist dass es relativ langsam ist. Im Grunde ist es wie eine interpretierte Sprache. Generierter Code ist schneller, da der Compiler für den bestimmten Typ optimiert werden kann, während DynamicMessage
muss mit jedem Typ umgehen können.
Allerdings gibt es wirklich keinen Weg dazu. Selbst wenn Sie den Code-Generator ausführen und die Klasse zur Laufzeit kompilieren, wäre der Code, der die neue Klasse verwendet, immer noch Code, den Sie zuvor geschrieben haben, bevor Sie wussten, welchen Typ Sie verwenden würden. Daher muss es immer noch eine reflektions- oder reflexionsähnliche Schnittstelle verwenden, um auf die Nachricht zuzugreifen, und das wird langsamer sein, als wenn der Code für den spezifischen Typ handgeschrieben wäre.
Nun, das hängt davon ab. Was wird der Client eigentlich tun, um mit diesem Schema, das er vom Server erhält, zu tun ?Das Übertragen eines Schemas über die Leitung macht den Client nicht mit der Version des Protokolls kompatibel - der Client muss verstehen , was das Protokoll bedeutet. Wenn das Protokoll rückwärtskompatibel geändert wurde, bedeutet dies fast sicher, dass sich die Bedeutung des Protokolls geändert hat und der Clientcode aktualisiert werden muss, Schemaübertragung oder nicht. Die einzige Zeit, in der Sie erwarten können, dass der Client ohne Aktualisierung weiterarbeitet, ist, wenn der Client nur eine generische Operation ausführt, die nur vom Nachrichteninhalt, nicht aber von der Nachrichtenbedeutung abhängt - beispielsweise könnte der Client die Nachricht in JSON konvertieren ohne zu wissen, was es bedeutet. Dies ist jedoch relativ ungewöhnlich, insbesondere am Client-Ende einer Anwendung. Aus diesem Grund sendet Protobufs standardmäßig keine Typinformationen - weil es normalerweise nutzlos ist, denn wenn der Empfänger die Bedeutung nicht kennt, ist das Schema irrelevant.
Wenn das Problem darin besteht, dass der Server Nachrichten an den Client sendet, die überhaupt nicht interpretiert werden sollen, sondern nur zu einem späteren Zeitpunkt an den Server zurückgeschickt werden, benötigt der Client das Schema überhaupt nicht . Übermitteln Sie die Nachricht einfach als bytes
und analysieren Sie sie nicht. Beachten Sie, dass ein bytes
-Feld, das eine codierte Nachricht vom Typ Foo
enthält, auf dem Draht genauso aussieht wie ein Feld, dessen Typ tatsächlich als Foo
deklariert ist. Sie könnten den Client und den Server gegen geringfügig unterschiedliche Versionen der Datei .proto
kompilieren, wobei der Client ein bestimmtes Feld als bytes
sieht, während der Server es als Unternachricht ansieht, um die Notwendigkeit für den Client zu vermeiden sich der Definition dieser Unternachricht bewusst sein.
''
Für Java ist die folgende Wrapper-API ("protobuf-dynamic") möglicherweise einfacher zu verwenden als die ursprüngliche protobuf-API:
Zum Beispiel:
%Vor%Dynamische Schemas können in einigen Anwendungen nützlich sein, um Änderungen zu verteilen, ohne Code neu zu kompilieren (etwa in einem dynamisch typisierten System). Sie können auch sehr nützlich für "dumme" Anwendungen sein, die kein semantisches Verständnis erfordern (sagen wir ein Datenbrowser-Tool)
Tags und Links java protocol-buffers