Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
mwq0106 committed Sep 4, 2020
1 parent 34565f4 commit bb342f3
Showing 1 changed file with 3 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ public class DemoController {

关键参数servicePath,serviceName,parameterType。每次进行RPC调用时都会生成一个相应的包装类,将服务路径,对应的其实就是各个语言中的包名+类名,装入servicePath中,调用方法名装入serviceName中,还有参数类型,这里使用了string类型的数组。在进行RPC调用时,将会通过servicePath定位到各个语言中的服务对象,这个服务对象对应于各个语言中对象,在对应的服务中使用类似于HashMap的方式存储服务对象,key值即是servicePath,value值则是服务对象。serviceName则是对象中的各个方法名。

parameterType则是一个字符串数组,它是实现跨语言RPC的核心设计之一,parameterType是数组是因为每次调用有可能包含多个参数,是字符串是因为我们会在各个服务中又保存一份HashMap,key值是string,来源于protobuf中的package名+ message名,所以我们要求进行RPC调用时,方法的参数以及返回值都必须要是protobuf生成的对象,并且声明了package,package+message将会用于定位相应的参数类型,value则是该参数在各个语言中的参数类型,可以根据该参数类型生成对应的参数实例,然后用于反序列化接收到的二进制数据,比如在java中就是class对象,在go中则是kind对象,我们可以根据该类型生成对应的对象实例,所以因为这个原因,在进行RPC调用时,每个参数与返回值都必须是在客户端与服务端都必须共同持有。本质上来说,我们使用这种映射解决了二进制数据转为多个protobuf对象的问题。所以我们区分了body1与body2的概念,body1是用于传输调用服务路径,方法名,方法类型。Body2则是调用时的方法实参,每个实参对应的二进制数据前面都有一个int表示当前实参的长度,我们只需按长度读取即可,并且body1中的parameterType数组也能标识出对应实参的类型,parameterType数组长度与body2的数量相等,如假设parameterType[0]是字符串tutorial.Test2.Person,我们可以去HashMap中取得java中的tutorial.Test2.Person class对象,通过该class对象生成类实例,再通过类实例去反序列化二进制数据,从而得到方法实参。通过以上body1转为request包装对象,request包装对象中又含有方法调用的参数信息,参数信息以字符串形式存储,再将字符串映射为参数类型,类型再生成对象,对象再去反序列化二进制数据的方式,解决了使用protobuf作为跨语言rpc调用的关键步骤。
parameterType则是一个字符串数组,它是实现跨语言RPC的核心设计之一,parameterType是数组是因为每次调用有可能包含多个参数,是字符串是因为我们会在各个服务中又保存一份HashMap,key值是string,来源于protobuf中的package名+ message名,所以我们要求进行RPC调用时,方法的参数以及返回值都必须要是protobuf生成的对象,并且声明了package,package+message将会用于定位相应的参数类型,value则是该参数在各个语言中的参数类型,可以根据该参数类型生成对应的参数实例,然后用于反序列化接收到的二进制数据,比如在java中就是class对象,在go中则是kind对象,我们可以根据该类型生成对应的对象实例,所以因为这个原因,在进行RPC调用时,每个参数与返回值都必须是在客户端与服务端都必须共同持有。本质上来说,我们使用这种映射解决了二进制数据转为多个protobuf对象的问题。

所以我们区分了body1与body2的概念,body1是用于传输调用服务路径,方法名,方法类型。Body2则是调用时的方法实参,每个实参对应的二进制数据前面都有一个int表示当前实参的长度,我们只需按长度读取即可,并且body1中的parameterType数组也能标识出对应实参的类型,parameterType数组长度与body2的数量相等,如假设parameterType[0]是字符串tutorial.Test2.Person,我们可以去HashMap中取得java中的tutorial.Test2.Person class对象,通过该class对象生成类实例,再通过类实例去反序列化二进制数据,从而得到方法实参。通过以上body1转为request包装对象,request包装对象中又含有方法调用的参数信息,参数信息以字符串形式存储,再将字符串映射为参数类型,类型再生成对象,对象再去反序列化二进制数据的方式,解决了使用protobuf作为跨语言rpc调用的关键步骤。

总结一遍协议的解析过程,在进行一次协议解析时,首先会根据魔数标识这是一个rpc协议的开始,然后读取header中的序列化类型,消息ID等,发现是使用protobuf作为序列化方式,然后再读取body1长度,使用RequestInner类去反序列化body1中的二进制数据,得到调用的一些基本信息,然后又根据RequestInner类中的parameterType字符串数组,得到调用参数类型的信息,本地持有一个parameterType的映射表,key值是字符串,value值是对象类型,接下来读取body2的信息,先根据parameterType的第一个值,得到第一个参数的类型,然后根据该类型得到第一个参数的对象实例,然后使用这个对象实例去反序列化第一个参数的二进制数据,第一个参数的二进制数据我们使用了int+body的格式去传输,先读一个int,得到第一个参数的长度,然后再读取相应长度的数据,即可得到第一个参数的二进制数据,从而完成了第一个参数的反序列化过程,第二第三个等参数的解析也是使用类似的思想,从而完成了一次rpc协议的解析过程,并且通过这种方式,是可以做到跨语言rpc的,理论上只要protobuf支持的语言,我们都可以做rpc。

Expand Down

0 comments on commit bb342f3

Please sign in to comment.