??xml version="1.0" encoding="utf-8" standalone="yes"?>天堂在线第六区,国产精品福利在线观看网址,精品女同一区二区三区在线观看http://www.aygfsteel.com/DLevin/category/54894.htmlIn 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 -Sinatrazh-cnMon, 03 Aug 2015 11:21:43 GMTMon, 03 Aug 2015 11:21:43 GMT60深入Protobuf源码QDescriptor、Message、RPC框架http://www.aygfsteel.com/DLevin/archive/2015/04/01/424012.htmlDLevinDLevinWed, 01 Apr 2015 01:31:00 GMThttp://www.aygfsteel.com/DLevin/archive/2015/04/01/424012.htmlhttp://www.aygfsteel.com/DLevin/comments/424012.htmlhttp://www.aygfsteel.com/DLevin/archive/2015/04/01/424012.html#Feedback1http://www.aygfsteel.com/DLevin/comments/commentRss/424012.htmlhttp://www.aygfsteel.com/DLevin/services/trackbacks/424012.htmlDescriptor框架寚woptimize_for?/span>LITE_RUNTIME?/span>proto文gQ?/span>protobuf~译器会在编译出?/span>Java代码文g末尾d一?/span>FileDescriptor静态字D以描述?/span>proto文g定义时的所有元数据信息、ؓ每个message对象定义一?/span>Descriptor静态字D以描述?/span>message定义时的元数据信息、ؓ每个message对象定义一?/span>FieldAccessorTable静态字D는于用反读?/span>/讄某个字段的值等Q以提供GeneratedMessage中方法的反射实现Q:    
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;

?/span>protobuf中存在多U类型的元数据描q类Q?/span>

1.     FileDescriptorQ对一?/span>proto文g的描qͼ它包含文件名、包名、选项Q如java_package?/span>java_outer_classname{)、文件中定义的所?/span>message、文件中定义的所?/span>enum、文件中定义的所?/span>service、文件中所有定义的extension、文件中定义的所有依赖文ӞimportQ等。在FileDescriptor中还存在一?/span>DescriptorPool实例Q它保存了所有的dependencies(依赖文g?/span>FileDescriptor)?/span>name?/span>GenericDescriptor的映、字D到FieldDescriptor的映、枚N?/span>EnumValueDescriptor的映,从而可以从?/span>DescriptorPool中查扄关的信息Q因而可以通过名字?/span>FileDescriptor中查?/span>Message?/span>Enum?/span>Service?/span>Extensions{?/span>

2.   DescriptorQ对一?/span>message定义的描qͼ它包含该message定义的名字、所有字Dc内?/span>message、内?/span>enum、关联的FileDescriptor{。可以用字D名或字D号查找FieldDescriptor?/span>

3.   FieldDescriptorQ对一个字D|扩展字段定义的描qͼ它包含字D名、字D号、字D늱型、字D定?/span>(required/optional/repeated/packed)、默认倹{是否是扩展字段以及和它兌?/span>Descriptor/FileDescriptor{?/span>

4.   EnumDescriptorQ对一?/span>enum定义的描qͼ它包?/span>enum名、全名、和它关联的FileDescriptor。可以用枚N或枚丑ր查?/span>EnumValueDescriptor?/span>

5.   EnumValueDescriptorQ对一个枚N定义的描qͼ它包含枚丑֐、枚丑ր{关联的EnumDescriptor/FileDescriptor{?/span>

6.   ServiceDescriptorQ对一?/span>service定义的描qͼ它包?/span>service名、全名、关联的FileDescriptor{?/span>

7.   MethodDescriptorQ对一个在service中的method的描qͼ它包?/span>method名、全名、参数类型、返回类型、关联的FileDescriptor/ServiceDescriptor{?/span>

最后,protobuf~译生成的代码末还有一?/span>descriptorData字符串数l,它是序列化后?/span>FileDescriptorProto数据Q在静态初始化块中可以调用FileDescriptor.internalBuildGeneratedFileFrom()Ҏ构造整?/span>FileDescriptor实例Q在完成FileDescriptor的构造后Q还会回调传入的InternalDescriptorAssigner实例以初始化其他的静态字D,如以上提到的所有的静态字Dc?br />

?/span>protobuf?/span>Descriptor的类图:


Message、MessageLite框架

序列化和反序列化?/span>protobuf最基础的框Ӟ它?/span>MessageLite/Message接口来抽象一个可序列化的实例Q?/span>q且使用Builder从字节数l或输入字节中构徏MessageLite/Message实例Q?/span>MessageLite?/span>Message内部都定义了自己?/span>Builderc,他们个字l承?/span>MessageLiteOrBuilder以及MessageOrBuilerQ它们定义了MessageLite/Message和它们各?/span>Buildercȝ共同接口?/span>

MessageLiteOrBuilder接口只定义了MessageLite?/span>MessageLite.Builder两个接口共有的两个方法:getDefaultInstanceForType()Ҏ获取一个当前还未初始化的当?/span>Message实例(没有字段被赋|因而所有字D返回默认|?/span>repeat字段q回I,在当?/span>protobuf 2.5.0的实CQ它q回的是一个单例,和每个生成的静态方?/span>getDefaultInstance()q回相同的实?/span>)Q?/span>isInitialized()Ҏ用来判断是否所?/span>required字段已经被赋倹{?/span>MessageLite接口中定义了两个writeTo()Ҏ分别当前实例序列化q写入输出字节流中,而另一?/span>writeDelimitedTo()Ҏ则在写入之前当前实例的总长度写入输出字节流中(以可变长32?/span>Int~码方式Q,从而可以同时向一个输出字节流中写入多?/span>Message实例Q?/span>MessageLite中还定义了获取当?/span>MessageLite在序列化成字节流后的d节数的方?/span>getSerializedSize()Q两个直接返回字节数l的toByteArray()/toByteString()ҎQ以及获取它?/span>Parser实例(getParserForType())和返回它?/span>Builder实例(toBuilder()Q创Z个新?/span>Builder实例/newBuilderForType()Q用当前MessageLitecd始化一个新?/span>Builder实例q返?/span>)Ҏ。其?/span>Builder接口用于从字节流或字节数l中解析q构?/span>MessageLite对象(各种版本?/span>mergeFrom()ҎQ如果发送端写入?/span>MessageLite字节长度Q则使用mergeDelimitedFrom()Ҏ)Q最?/span>Builder使用build()Ҏ构?/span>MessageLite对象Q此时如果有required字段q未被设|,会抛?/span>UninitializedMessageExceptionQؓ了避免抛出异常,可以使用buildPartial()ҎQ另?/span>Builderq定义了clone()?/span>clear()ҎQ在生成的每?/span>Message对象中都定义了一?/span>newBuilder()静态方法,一般用该静态方法初始化一?/span>Builder实例?/span>Parser接口也定义了各个版本?/span>parseFrom()/parsePartialFrom()/parseDelimitedFrom()/parsePartialDelimitedFrom()Ҏ用来从字节数l或字节中解析?/span>Message实例Q在生成的代码中Q?/span>Builder的实现直接调?/span>Parser实现cM的方法?/span>

在大部分情况下,MessageLite已经能完成所有的序列化和反序列化操作了,特别是一些资源有限额手持讑֤Q它如果q行整个protobuf库会昑־太耗资源;可以?/span>.proto文g中加入一下指令来告诉protobuf~译器只需要生成实?/span>MessageLite的类Q?/span>

option optimize_for = LITE_RUNTIME

然而对一般的ServerE序来说Q我们ƈ不在乎这点资源的损耗,因而会选择实现Message接口Q它相比MessageLiteQ添加了Descriptors相关的支持,x持?/span>FieldDescriptor来构?/span>Message.Builder实例q最l构?/span>Message实例?/span>

MessageOrBuilder接口l承?/span>MessageLiteOrBuilder接口Q它定义?/span>Message?/span>Message.Builder共有的接口,x加了Descriptor?/span>FieldDescriptor{相关的扩展。由于实?/span>Message?/span>Message.Builder接口的类保存了所?/span>Message定义时具有的信息(文g名、包名、字D列表等Q用各U?/span>DescriptorcL抽象)Q因而我们可以?/span>Message/Message.Builderc获取到更多的信息,如一?/span>Message/Message.Builder没有赋值所?/span>required的字D,可以使用findInitializationErrors()Ҏ来获取所有未赋值的字段列表(字段的全路径名,getInitializationErrorString()是这个列表的字符串Ş式表达,Z提升性能Q徏议?/span>isInitialized()Ҏ先做初步判断Q因为它更快)Q另外在MessageOrBuilder中还定义了当?/span>Message对应?/span>Descriptor实例Q?/span>getDescriptorForType()ҎQ获取所有已l赋值的FieldDescriptor到其值的一?/span>MapQ?/span>getAllFields()Q通过FieldDescriptor取得其|getField()Q判断一个字D|否已l被赋|hasField()Q获?/span>repeated字段?/span>countQ?/span>getRepeatedFieldCount()Q通过FieldDescriptor以及index获取repeated字段?/span>index处的|getRepeatedField()Q获取未知的字段Q?/span>getUnknownFields()?/span>Message接口除了l承?/span>MessageOrBuilder接口的方法,q没有定义多余的ҎQ只是添加了equals?/span>hashCode?/span>toStringҎ的定义。?/span>Message.Builder接口除了l承?/span>MessageOrBuilder接口以外Q它q定义了ZFieldDescriptor的方法,如通过FieldDescriptor创徏/获取Builder实例Q?/span>newBuilderForFileld()/getFieldBuilder()Q通过FieldDescriptor/清除字段的|setField()/clearField()/setRepeatedField()/addRepeatedField()Q以及设|?/span>UnknownFieldsQ?/span>setUnknownFields()/mergeUnknownFields()?/span>

 

MessageLite/Messagecd如下Q?/span>



RPC框架

除了序列化框Ӟprotobufq定义了一套简单的RPC框架。之所以说单是因ؓ它定义的Service层接口的协议Q而没有具体和传输相关的实玎ͼ而只是将传输相关的逻辑抽象?/span>RpcChannel?/span>BlockingRpcChannel分别用于表示同步和一步方式的ServiceҎ调用Q而至于底层用什么样的协议和框架Q由用户自己军_q实现?/span>

所?/span>RPC框架Q从用户角度上最基本的就是定义客L和服务器端的协议Q即服务器端暴露Z么样的接口供客户端调用,q个接口定义了服务器在一?/span>Host的某个(些)端口上接收某些请求数据,q期望能q回的响应。其中服务器和端口号属于传输实现的范_protobuf只是?/span>RpcChannel/BlockingRpcChannel的概念做了抽象,而没有给出具体实玎ͼ而接收某个请求数据以及期待的响应数据Q在protobuf使用Service/BlockingService抽象来定义,q且q也?/span>protobuf?/span>RPC框架的定义部分,其中Service?/span>RpcChannel共同构成异步方式?/span>RPC框架Q?/span>BlockingService?/span>BlockingRpcChannel共同构成了同步(dQ方式的RPC框架?/span>

从底层实现的角度Q一?/span>RPC调用是客户端发送一些请求数据给服务器,服务器解析ƈ处理q些h数据Q然后将响应数据q回l客L。ؓ了隐藏内部实现细节,提升写代码的效率Q?/span>RPC这一q程装成方法调用,即不同的h用不同的Ҏ表达Q这是protobuf?/span>RPC的定义。在protobuf中,定义一?/span>PRC接口比较单:首先开?/span>RPC功能Q然后用service关键字定义一个接口,在接口中使用rpc关键字定义一个方法,Ҏ包含Ҏ名、方法参数、返回|其中Ҏ参数和返回值都必须是一?/span>messagecdQƈ且只能有一个:

option java_generic_services = true;

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

?/span>protobuf~译生成的代码中Q它会生成一?/span>MyService抽象cdCService接口Q一般它只是作ؓ一个命名空_它内部定义了两个接口Q?/span>Interface?/span>BlockingInterface本别l承?/span>Service接口?/span>BlockingService接口Q用于抽象异步和同步方式?/span>RPCҎ调用Q这两个接口有两个实现类Q?/span>Stub?/span>BlockingStubQ他们分别接?/span>RpcChannel?/span>BlockingRpcChannel实例作ؓ构造函数参敎ͼ可以使用MyService中的静态方?/span>newStub()?/span>newBlockingStub()Ҏ获取他们各自实例Q他们主要用于客L的调用。在生成?/span>requestҎ中,除了request本n的参敎ͼq有一?/span>RpcController参数Q它用于处理?/span>RpcChannel/BlockingRpcChannel调用中的状态处理,如错误处理等Q用它可以L此次调用是否出错Q错误信息是什么等。在MyService中还定义了两个静态方?/span>newReflectiveService/newReflectiveBlockingServiceQ他们接?/span>Interface/BlockingInterface实例Qƈq回Service/BlockingService的实现实例(暂时q没有想C用他们的场景Q?/span>



?/span>MyService?/span>RPC框架实现中,在服务器端,实现MyService.Interface/MyService.BlockingInterface接口Q然后将它注册到?/span>RpcChannel/BlockingRpcChannel框架的实CQ在客户端则创徏一?/span>RpcChannel/BlockingRpcChannel实例Q传?/span>MyService.newStub()/MyService.newBlockingStub()Ҏ获取对应的实例,然后使用q个Stub/BlockingStub实例调用相应的方法即可?/span>



DLevin 2015-04-01 09:31 发表评论
]]>
深入Protobuf源码Q编码实?/title><link>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424011.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Wed, 01 Apr 2015 01:23:00 GMT</pubDate><guid>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424011.html</guid><wfw:comment>http://www.aygfsteel.com/DLevin/comments/424011.html</wfw:comment><comments>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424011.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.aygfsteel.com/DLevin/comments/commentRss/424011.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/DLevin/services/trackbacks/424011.html</trackback:ping><description><![CDATA[     摘要: 基本cd~码在前文有提到消息是一pd的基本类型以及其他消息类型的l合Q因而基本类型是probobuf~码实现的基Q这些基本类型有Q? .proto Type Java Type C++ Type Wire Type double double double WI...  <a href='http://www.aygfsteel.com/DLevin/archive/2015/04/01/424011.html'>阅读全文</a><img src ="http://www.aygfsteel.com/DLevin/aggbug/424011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/DLevin/" target="_blank">DLevin</a> 2015-04-01 09:23 <a href="http://www.aygfsteel.com/DLevin/archive/2015/04/01/424011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入Protobuf源码Q概q、用以及代码生成实?/title><link>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424009.html</link><dc:creator>DLevin</dc:creator><author>DLevin</author><pubDate>Wed, 01 Apr 2015 01:13:00 GMT</pubDate><guid>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424009.html</guid><wfw:comment>http://www.aygfsteel.com/DLevin/comments/424009.html</wfw:comment><comments>http://www.aygfsteel.com/DLevin/archive/2015/04/01/424009.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/DLevin/comments/commentRss/424009.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/DLevin/services/trackbacks/424009.html</trackback:ping><description><![CDATA[     摘要: 概述 捣鼓hdfs、yarn、hbase、zookeeper的代码一q多了,是时候整理一下了。在hadoop Q?.5.2Q中protobuf是节点之间以及客L和各个节炚w信的基序列化框Ӟ协议Q,而基于avro和Writable的序列化框架则是q个协议里的payloadQ因而这一pd的文章打从protobufq个框架开始入?版本2.5.0)?从抽象的角度来说Qprotobuf框架?..  <a href='http://www.aygfsteel.com/DLevin/archive/2015/04/01/424009.html'>阅读全文</a><img src ="http://www.aygfsteel.com/DLevin/aggbug/424009.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/DLevin/" target="_blank">DLevin</a> 2015-04-01 09:13 <a href="http://www.aygfsteel.com/DLevin/archive/2015/04/01/424009.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ľ</a>| <a href="http://" target="_blank">ũ</a>| <a href="http://" target="_blank">÷</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank">Ǭ</a>| <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank">Ϫ</a>| <a href="http://" target="_blank">⳵</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ػʵ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʵ</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank">ʯɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̶</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʼ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>