<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    Descriptor框架

    對非optimize_forLITE_RUNTIMEproto文件,protobuf編譯器會在編譯出的Java代碼文件末尾添加一個(gè)FileDescriptor靜態(tài)字段以描述該proto文件定義時(shí)的所有元數(shù)據(jù)信息、為每個(gè)message對象定義一個(gè)Descriptor靜態(tài)字段以描述該message定義時(shí)的元數(shù)據(jù)信息、為每個(gè)message對象定義一個(gè)FieldAccessorTable靜態(tài)字段用于使用反射讀取/設(shè)置某個(gè)字段的值等(以提供GeneratedMessage中方法的反射實(shí)現(xiàn)):    
    private static Descriptor inter-nal_static_levin_protobuf_Result_descriptor;
    private static FieldAccessorTable inter-nal_static_levin_protobuf_Result_fieldAccessorTable;
    private static Descriptor inter-nal_static_levin_protobuf_SearchResponse_descriptor;
    private static FieldAccessorTable inter-nal_static_levin_protobuf_SearchResponse_fieldAccessorTable;
    private static FileDescriptor descriptor;

    protobuf中存在多種類型的元數(shù)據(jù)描述類:

    1.     FileDescriptor:對一個(gè)proto文件的描述,它包含文件名、包名、選項(xiàng)(如java_packagejava_outer_classname等)、文件中定義的所有message、文件中定義的所有enum、文件中定義的所有service、文件中所有定義的extension、文件中定義的所有依賴文件(import)等。在FileDescriptor中還存在一個(gè)DescriptorPool實(shí)例,它保存了所有的dependencies(依賴文件的FileDescriptor)nameGenericDescriptor的映射、字段到FieldDescriptor的映射、枚舉項(xiàng)到EnumValueDescriptor的映射,從而可以從該DescriptorPool中查找相關(guān)的信息,因而可以通過名字從FileDescriptor中查找MessageEnumServiceExtensions等。

    2.   Descriptor:對一個(gè)message定義的描述,它包含該message定義的名字、所有字段、內(nèi)嵌message、內(nèi)嵌enum、關(guān)聯(lián)的FileDescriptor等。可以使用字段名或字段號查找FieldDescriptor

    3.   FieldDescriptor:對一個(gè)字段或擴(kuò)展字段定義的描述,它包含字段名、字段號、字段類型、字段定義(required/optional/repeated/packed)、默認(rèn)值、是否是擴(kuò)展字段以及和它關(guān)聯(lián)的Descriptor/FileDescriptor等。

    4.   EnumDescriptor:對一個(gè)enum定義的描述,它包含enum名、全名、和它關(guān)聯(lián)的FileDescriptor。可以使用枚舉項(xiàng)或枚舉值查找EnumValueDescriptor

    5.   EnumValueDescriptor:對一個(gè)枚舉項(xiàng)定義的描述,它包含枚舉名、枚舉值、關(guān)聯(lián)的EnumDescriptor/FileDescriptor等。

    6.   ServiceDescriptor:對一個(gè)service定義的描述,它包含service名、全名、關(guān)聯(lián)的FileDescriptor等。

    7.   MethodDescriptor:對一個(gè)在service中的method的描述,它包含method名、全名、參數(shù)類型、返回類型、關(guān)聯(lián)的FileDescriptor/ServiceDescriptor等。

    最后,protobuf編譯生成的代碼末尾還有一個(gè)descriptorData字符串?dāng)?shù)組,它是序列化后的FileDescriptorProto數(shù)據(jù),在靜態(tài)初始化塊中可以調(diào)用FileDescriptor.internalBuildGeneratedFileFrom()方法構(gòu)造整個(gè)FileDescriptor實(shí)例,在完成FileDescriptor的構(gòu)造后,還會回調(diào)傳入的InternalDescriptorAssigner實(shí)例以初始化其他的靜態(tài)字段,如以上提到的所有的靜態(tài)字段。

    protobufDescriptor的類圖:


    Message、MessageLite框架

    序列化和反序列化是protobuf最基礎(chǔ)的框架,它使用MessageLite/Message接口來抽象一個(gè)可序列化的實(shí)例,并且使用Builder從字節(jié)數(shù)組或輸入字節(jié)流中構(gòu)建MessageLite/Message實(shí)例,MessageLiteMessage內(nèi)部都定義了自己的Builder類,他們個(gè)字繼承自MessageLiteOrBuilder以及MessageOrBuiler,它們定義了MessageLite/Message和它們各自Builder類的共同接口。

    MessageLiteOrBuilder接口只定義了MessageLiteMessageLite.Builder兩個(gè)接口共有的兩個(gè)方法:getDefaultInstanceForType()方法獲取一個(gè)當(dāng)前還未初始化的當(dāng)前Message實(shí)例(沒有字段被賦值,因而所有字段返回默認(rèn)值,對repeat字段返回空,在當(dāng)前protobuf 2.5.0的實(shí)現(xiàn)中,它返回的是一個(gè)單例,和每個(gè)生成的靜態(tài)方法getDefaultInstance()返回相同的實(shí)例)isInitialized()方法用來判斷是否所有required字段已經(jīng)被賦值。MessageLite接口中定義了兩個(gè)writeTo()方法分別將當(dāng)前實(shí)例序列化并寫入輸出字節(jié)流中,而另一個(gè)writeDelimitedTo()方法則在寫入之前將當(dāng)前實(shí)例的總長度寫入輸出字節(jié)流中(以可變長32Int編碼方式),從而可以同時(shí)向一個(gè)輸出字節(jié)流中寫入多個(gè)Message實(shí)例;MessageLite中還定義了獲取當(dāng)前MessageLite在序列化成字節(jié)流后的總字節(jié)數(shù)的方法getSerializedSize(),兩個(gè)直接返回字節(jié)數(shù)組的toByteArray()/toByteString()方法,以及獲取它的Parser實(shí)例(getParserForType())和返回它的Builder實(shí)例(toBuilder()-創(chuàng)建一個(gè)新的Builder實(shí)例/newBuilderForType()-用當(dāng)前MessageLite類初始化一個(gè)新的Builder實(shí)例并返回)方法。其中Builder接口用于從字節(jié)流或字節(jié)數(shù)組中解析并構(gòu)造MessageLite對象(各種版本的mergeFrom()方法,如果發(fā)送端寫入了MessageLite字節(jié)長度,則使用mergeDelimitedFrom()方法),最后Builder使用build()方法構(gòu)造MessageLite對象,此時(shí)如果有required字段還未被設(shè)置,會拋出UninitializedMessageException,為了避免拋出異常,可以使用buildPartial()方法;另外Builder還定義了clone()clear()方法;在生成的每個(gè)Message對象中都定義了一個(gè)newBuilder()靜態(tài)方法,一般使用該靜態(tài)方法初始化一個(gè)Builder實(shí)例。Parser接口也定義了各個(gè)版本的parseFrom()/parsePartialFrom()/parseDelimitedFrom()/parsePartialDelimitedFrom()方法用來從字節(jié)數(shù)組或字節(jié)流中解析出Message實(shí)例,在生成的代碼中,Builder的實(shí)現(xiàn)直接調(diào)用Parser實(shí)現(xiàn)類中的方法。

    在大部分情況下,MessageLite已經(jīng)能完成所有的序列化和反序列化操作了,特別是一些資源有限額手持設(shè)備,它如果運(yùn)行整個(gè)protobuf庫會顯得太耗資源;可以在.proto文件中加入一下指令來告訴protobuf編譯器只需要生成實(shí)現(xiàn)MessageLite的類:

    option optimize_for = LITE_RUNTIME

    然而對一般的Server程序來說,我們并不在乎這點(diǎn)資源的損耗,因而會選擇實(shí)現(xiàn)Message接口,它相比MessageLite,添加了Descriptors相關(guān)的支持,即支持使用FieldDescriptor來構(gòu)建Message.Builder實(shí)例并最終構(gòu)建Message實(shí)例。

    MessageOrBuilder接口繼承自MessageLiteOrBuilder接口,它定義了MessageMessage.Builder共有的接口,即添加了DescriptorFieldDescriptor等相關(guān)的擴(kuò)展。由于實(shí)現(xiàn)MessageMessage.Builder接口的類保存了所有Message定義時(shí)具有的信息(文件名、包名、字段列表等,使用各種Descriptor類來抽象),因而我們可以使用Message/Message.Builder類獲取到更多的信息,如一個(gè)Message/Message.Builder沒有賦值所有required的字段,可以使用findInitializationErrors()方法來獲取所有未賦值的字段列表(字段的全路徑名,getInitializationErrorString()是這個(gè)列表的字符串形式表達(dá),為了提升性能,建議使用isInitialized()方法先做初步判斷,因?yàn)樗?/span>);另外在MessageOrBuilder中還定義了當(dāng)前Message對應(yīng)的Descriptor實(shí)例:getDescriptorForType()方法,獲取所有已經(jīng)賦值的FieldDescriptor到其值的一個(gè)MapgetAllFields(),通過FieldDescriptor取得其值:getField(),判斷一個(gè)字段是否已經(jīng)被賦值:hasField(),獲取repeated字段的countgetRepeatedFieldCount(),通過FieldDescriptor以及index獲取repeated字段在index處的值:getRepeatedField(),獲取未知的字段:getUnknownFields()Message接口除了繼承自MessageOrBuilder接口的方法,并沒有定義多余的方法,只是添加了equalshashCodetoString方法的定義。而Message.Builder接口除了繼承自MessageOrBuilder接口以外,它還定義了基于FieldDescriptor的方法,如通過FieldDescriptor創(chuàng)建/獲取Builder實(shí)例:newBuilderForFileld()/getFieldBuilder(),通過FieldDescriptor設(shè)置/清除字段的值:setField()/clearField()/setRepeatedField()/addRepeatedField(),以及設(shè)置UnknownFieldssetUnknownFields()/mergeUnknownFields()

     

    MessageLite/Message類圖如下:



    RPC框架

    除了序列化框架,protobuf還定義了一套簡單的RPC框架。之所以說簡單是因?yàn)樗x的Service層接口的協(xié)議,而沒有具體和傳輸相關(guān)的實(shí)現(xiàn),而只是將傳輸相關(guān)的邏輯抽象成RpcChannelBlockingRpcChannel分別用于表示同步和一步方式的Service方法調(diào)用,而至于底層用什么樣的協(xié)議和框架,由用戶自己決定并實(shí)現(xiàn)。

    所謂RPC框架,從用戶角度上最基本的就是定義客戶端和服務(wù)器端的協(xié)議,即服務(wù)器端暴露出什么樣的接口供客戶端調(diào)用,這個(gè)接口定義了服務(wù)器在一個(gè)Host的某個(gè)(些)端口上接收某些請求數(shù)據(jù),并期望能返回的響應(yīng)。其中服務(wù)器和端口號屬于傳輸實(shí)現(xiàn)的范疇,protobuf只是用RpcChannel/BlockingRpcChannel的概念做了抽象,而沒有給出具體實(shí)現(xiàn);而接收某個(gè)請求數(shù)據(jù)以及期待的響應(yīng)數(shù)據(jù),在protobuf使用Service/BlockingService抽象來定義,并且這也是protobufRPC框架的定義部分,其中ServiceRpcChannel共同構(gòu)成異步方式的RPC框架,而BlockingServiceBlockingRpcChannel共同構(gòu)成了同步(阻塞)方式的RPC框架。

    從底層實(shí)現(xiàn)的角度,一個(gè)RPC調(diào)用就是客戶端發(fā)送一些請求數(shù)據(jù)給服務(wù)器,服務(wù)器解析并處理這些請求數(shù)據(jù),然后將響應(yīng)數(shù)據(jù)返回給客戶端。為了隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié),提升寫代碼的效率,RPC將這一過程封裝成方法調(diào)用,即不同的請求用不同的方法表達(dá),這就是protobufRPC的定義。在protobuf中,定義一個(gè)PRC接口比較簡單:首先開啟RPC功能,然后用service關(guān)鍵字定義一個(gè)接口,在接口中使用rpc關(guān)鍵字定義一個(gè)方法,方法包含方法名、方法參數(shù)、返回值,其中方法參數(shù)和返回值都必須是一個(gè)message類型,并且只能有一個(gè):

    option java_generic_services = true;

    service MyService {
        rpc request(SearchRequest) returns(SearchResponse);
    }

    protobuf編譯生成的代碼中,它會生成一個(gè)MyService抽象類實(shí)現(xiàn)了Service接口,一般它只是作為一個(gè)命名空間,它內(nèi)部定義了兩個(gè)接口:InterfaceBlockingInterface本別繼承自Service接口和BlockingService接口,用于抽象異步和同步方式的RPC方法調(diào)用;這兩個(gè)接口有兩個(gè)實(shí)現(xiàn)類:StubBlockingStub,他們分別接收RpcChannelBlockingRpcChannel實(shí)例作為構(gòu)造函數(shù)參數(shù),可以使用MyService中的靜態(tài)方法newStub()newBlockingStub()方法獲取他們各自實(shí)例,他們主要用于客戶端的調(diào)用。在生成的request方法中,除了request本身的參數(shù),還有一個(gè)RpcController參數(shù),它用于處理在RpcChannel/BlockingRpcChannel調(diào)用中的狀態(tài)處理,如錯(cuò)誤處理等,使用它可以獲知此次調(diào)用是否出錯(cuò),錯(cuò)誤信息是什么等。在MyService中還定義了兩個(gè)靜態(tài)方法newReflectiveService/newReflectiveBlockingService,他們接收Interface/BlockingInterface實(shí)例,并返回Service/BlockingService的實(shí)現(xiàn)實(shí)例(暫時(shí)還沒有想到使用他們的場景)。



    MyServiceRPC框架實(shí)現(xiàn)中,在服務(wù)器端,實(shí)現(xiàn)MyService.Interface/MyService.BlockingInterface接口,然后將它注冊到對RpcChannel/BlockingRpcChannel框架的實(shí)現(xiàn)中;在客戶端則創(chuàng)建一個(gè)RpcChannel/BlockingRpcChannel實(shí)例,傳入MyService.newStub()/MyService.newBlockingStub()方法獲取對應(yīng)的實(shí)例,然后使用這個(gè)Stub/BlockingStub實(shí)例調(diào)用相應(yīng)的方法即可。

    posted on 2015-04-01 09:31 DLevin 閱讀(23688) 評論(1)  編輯  收藏 所屬分類: Protobuf

    FeedBack:
    # re: 深入Protobuf源碼-Descriptor、Message、RPC框架
    2015-06-12 15:51 | 孫超6106
    你好,請問你這類圖用什么工具生成的? 反向還是手動(dòng)??謝謝  回復(fù)  更多評論
      
    主站蜘蛛池模板: 亚洲色大18成人网站WWW在线播放| 亚洲高清无码综合性爱视频| 91短视频免费在线观看| 日韩精品无码一区二区三区免费| 国产真人无码作爱视频免费 | 亚洲高清国产AV拍精品青青草原 | 久久国产精品免费专区| 久久er国产精品免费观看2| 免费91最新地址永久入口 | 免费人成大片在线观看播放电影| 国产精品成人亚洲| 无忧传媒视频免费观看入口| 特级毛片A级毛片免费播放| 成人午夜免费视频| 永久免费AV无码网站国产| 日韩免费无码视频一区二区三区 | 国产成人精品日本亚洲语音| 猫咪免费人成在线网站| 亚洲精品视频免费| 国产日韩一区二区三免费高清| 免费观看男人吊女人视频| 亚洲w码欧洲s码免费| 在线观看免费大黄网站| 又色又污又黄无遮挡的免费视| 一本色道久久综合亚洲精品高清| 久久亚洲精品视频| 亚洲影视自拍揄拍愉拍| 男男黄GAY片免费网站WWW| 巨胸狂喷奶水视频www网站免费| 精品无码国产污污污免费网站| 国产无人区码卡二卡三卡免费| 免费的涩涩视频在线播放| 国产av无码专区亚洲国产精品| 亚洲AV无码专区国产乱码电影| 亚洲人成在线免费观看| 牛牛在线精品观看免费正| 无码人妻丰满熟妇区免费| 四虎成人精品一区二区免费网站 | 一个人免费高清在线观看 | 最近中文字幕mv免费高清在线 | 国产乱子精品免费视观看片|