protobuf的反射機制


反射機制

java在運行狀態時,能夠知道任意類的所有屬性和方法,都能夠調用任意對象的任意方法和屬性。這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。

C++本身沒有反射機制。protobuf通過proto文件生成相應的messageserviceprotobuf也通過proto文件提供反射機制,程序在運行時可以通過proto獲取任意message和任意service的屬性和方法,也可以在運行時調用message的屬性和方法。

獲取messageservice的屬性和方法

protobuf通過Descriptor獲取任意messageservice的屬性和方法,Descriptor主要包括了以下集中類型:

 

FileDescriptor   獲取proto文件中的DescriptorServiceDescriptor

Descriptor      獲取類message屬性和方法,包括FieldDescriptor  EnumDescriptor

FieldDescriptor   獲取message中各個字段的類型、標簽、名稱等

EnumDescriptor   獲取Enum中的各個字段名稱、值等

ServiceDescriptor 獲取service中的MethodDescriptor

MethodDescriptor 獲取各個rpc中的requestresponse、名稱等

 

當我們獲得proto文件的FileDescriptor時,我們就可以獲得所有的serviceDescriptorserviceServiceDescriptor,進而獲取其相應的字段或rpc。也就是說,如果能獲取到proto文件的FileDescriptor,就能所有的proto文件中的所有內容。

那么如何獲取proto文件的FileDescriptor呢?protobuf對應以下兩種不同的情況提供了相應的辦法

1、 使用protocproto文件並生成相應的.h.cpp文件。

這中情況下protobuf已經解析好proto文件,並將所有的Descriptor放在DescriptorPool中了。,可以根據proto的文件名,通過DescriptorPool獲取到相應的FileDescriptor,例如,現有test.proto文件,那么可以通過DescriptorPool::generated_pool()獲取到其FileDescriptor。其實,對於任意的messageservice,也都可以根據其名稱,通過DescriptorPool獲取相應的DescriptorServiceDescriptor。例如:

2、 只有proto文件,不使用protoc

這種情況需要去手動解析proto文件,然后再獲取FileDescriptor。還好protobuf提供了相應的解析器compiler,通過compiler可以很方便得獲取proto文件的FileDescriptor,具體如下:

 

調用message的屬性和方法

想要調用message的屬性和方法,就得先獲取相應的message對象。protobufmessage對象都是放在MessageFactory中的,可以通過Descriptor,具體如下:

 

有了message對象,並不能直接調用其對象和方法,因為所有的message對象都是Message*類型的,但不同的message對象的屬性和方法是不一樣的,在這里,Message*只是指向相應的message大小的地址空間,並不知道對應的message中到底有哪些屬性和方法。

protobuf是通過Reflection調用message的屬性和方法的。message中的方法只有對各個屬性的getset,而調用message的屬性其實也就是調用屬性的get。調用message的某一個屬性的get,就需要該屬性的Descriptor,通過Reflection獲取message獲取相應的值;調用message某一屬性的set,也需要該屬性的Descriptor,通過Reflection將相應的值寫入到message相應的屬性。例如:

 

反射機制的應用

有了反射機制,可以寫很多工具,比如:基於pb的自動化測試工具、pbjsonxml的工具、pb直接寫到數據庫的工具等。反射只是一種機制,有什么樣的應用場景需要你的想象力!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM