前言

通常 RPC 调用需要客户端使用服务端提供的接口,而具体的形式则是使用 jar 包,通过引用 jar 包获取接口的的具体信息,例如接口名称,方法名称,参数类型,返回值类型。

但也存在一些情况,例如客户端没有 jar 包,或者是跨语言的调用,这个时候,就需要客户端使用字符串进行泛化调用。

如何使用

还是根据官方的例子来看一下:

ConsumerConfig<GenericService> consumerConfig = new ConsumerConfig<GenericService>()
.setInterfaceId("com.alipay.sofa.rpc.quickstart.HelloService")
.setGeneric(true);
GenericService testService = consumerConfig.refer(); String result = (String) testService.$invoke("sayHello", new String[] { "java.lang.String" },new Object[] { "1111" });

我们看到,实际上,设置接口 ID 是和普通的调用时类似的,只是需要增加一个 Generic 属性为 true。

然后就返回了一个 GenericService 类型的代理对象,通过这个对象,就可以对服务发起调用,而调用的方式,则是使用 GenericService 的 $invoke 方法,需要传递方法名称,参数类型,参数值。并指定返回值。

SOFA 是如何实现的呢?

源码实现

既然和普通的调用只是变化了 Generic 属性,那么,我们就看看这个属性在哪些地方使用。

我们很快便找到了一个过滤器: ConsumerGenericFilter,该过滤器的生效条件则是 “客户端是否配置了泛型”。如果设置泛型,则添加到过滤链中。

而该过滤器的 invoke 方法肯定是对调用进行了一些特殊的操作,具体如下:

  1. 根据方法名称得到序列化的类型,例如普通序列化,泛型序列化,混合序列化。我们这里的例子返回的值是 0(普通序列化),然后设置序列化工厂类型,即普通序列化(根据方法名不同而不同)。
  2. 从 Request 对象中拿到方法名称,参数类型的字符串,方法参数。并重新设置到 Request 对象中,相当于重新整理了一遍。
  3. 然后根据刚刚设置的方法名重新设置调用类型。

这样就将泛型的调用修改成和普通调用一样了。

同时注意:发起调用时,该过滤器的默认 order 是 -18000,因此他会在大部分(除了异常处理和上下文)之前执行。

在使用 Bolt 的 RpcClient 进行调用的时候,会根据序列化类型决定是否进行泛型的序列化。

具体过程是,当调用时,会创建 InvokeContext 上下文,会在 Map 中存储自定义的序列化器,其中 key 是 SerializeFactoryType,value 是 0(我们这里),在 RpcRemoting 的 invokeXXX 方法中,会创建一个 RemotingCommand 对象,即执行 toRemotingCommand 方法,根据 InvokeContext 中的 SerializeFactoryType 获取到序列化工厂的枚举值,并设置到 RemotingCommand 对象中。

在 SofaRpcSerialization 类中,会根据 invokeContext 中存储的序列化枚举值得到序列化器,具体代码如下:

// 根据SerializeType信息决定序列化器
boolean genericSerialize = genericSerializeRequest(invokeContext);
if (genericSerialize) {
output.setSerializerFactory(genericSerializerFactory);
} else {
output.setSerializerFactory(serializerFactory);
}

根据SerializeType信息决定序列化器。而泛型的具体序列化器工厂则是 GenericMultipleClassLoaderSofaSerializerFactory 类,该类的会生成序列化器和反序列化器。并在 Bolt 中使用。

总结

从 SOFA 的设计中可以看出,泛化调用主要依赖于 GenericService 这个类和对应的 ConsumerGenericFilter 过滤器,如果一个客户端设置泛化了,那么调用过程中则会启用这个过滤器。

这个过滤器会将请求的数据重新整理。并修改成普通调用的样子。

同时也会设置一个泛型调用的序列化枚举放置在上下文中,上下文在 Bolt 中会根据枚举值动态获取不同的序列化器和反序列化器,对输出参数和返回值经进行处理。

SOFA 源码分析 — 泛化调用的更多相关文章

  1. SOFA 源码分析 —— 服务引用过程

    前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引 ...

  2. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  3. SOFA 源码分析 — 调用方式

    前言 SOFARPC 提供了多种调用方式满足不同的场景. 例如,同步阻塞调用:异步 future 调用,Callback 回调调用,Oneway 调用. 每种调用模式都有对应的场景.类似于单进程中的调 ...

  4. SOFA 源码分析 — 自动故障剔除

    前言 集群中通常一个服务有多个服务提供者.其中部分服务提供者可能由于网络,配置,长时间 fullgc ,线程池满,硬件故障等导致长连接还存活但是程序已经无法正常响应.单机故障剔除功能会将这部分异常的服 ...

  5. SOFA 源码分析 — 负载均衡和一致性 Hash

    前言 SOFA 内置负载均衡,支持 5 种负载均衡算法,随机(默认算法),本地优先,轮询算法,一致性 hash,按权重负载轮询(不推荐,已被标注废弃). 一起看看他们的实现(重点还是一致性 hash) ...

  6. SOFA 源码分析 — 预热权重

    前言 SOFA-RPC 支持根据权重对服务进行预热功能,具体地址:预热权重. 引用官方文档: 预热权重功能让客户端机器能够根据服务端的相应权重进行流量的分发.该功能也常被用于集群内少数机器的启动场景. ...

  7. SOFA 源码分析— 事件总线

    前言 大部分框架都是事件订阅功能,即观察者模式,或者叫事件机制.通过订阅某个事件,当触发事件时,回调某个方法.该功能非常的好用,而 SOFA 内部也设计了这个功能,并且内部大量使用了该功能.来看看是如 ...

  8. SOFA 源码分析 — 自定义线程池原理

    前言 在 SOFA-RPC 的官方介绍里,介绍了自定义线程池,可以为指定服务设置一个独立的业务线程池,和 SOFARPC 自身的业务线程池是隔离的.多个服务可以共用一个独立的线程池. API使用方式如 ...

  9. SOFA 源码分析 — 链路数据透传

    前言 SOFA-RPC 支持数据链路透传功能,官方解释: 链路数据透传功能支持应用向调用上下文中存放数据,达到整个链路上的应用都可以操作该数据. 使用方式如下,可分别向链路的 request 和 re ...

随机推荐

  1. 【一天一道LeetCode】#97. Interleaving String

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given s ...

  2. React Native控件只TextInput

    TextInput是一个允许用户在应用中通过键盘输入文本的基本组件.本组件的属性提供了多种特性的配置,譬如自动完成.自动大小写.占位文字,以及多种不同的键盘类型(如纯数字键盘)等等. 比如官网最简单的 ...

  3. jpa一对多映射案例

    订单和订单项就是一对多的关系.一个订单有多个订单项,一个订单项属于某个订单. 订单和订单项映射后的表结构如下: 订单表结构 订单项表结构 下面就以订单和订单项为例介绍多对多映射关系的实例开发 pers ...

  4. Dynamics Crm2011 Removes an option from an Option Set control

    应用场景:OptionSet中有N个option值,特定的条件下需要去除某些option的显示,例如在某个条件下我要红框中的两个option不显示 var purchasetype= Xrm.Page ...

  5. 命令行界面的C/S聊天室应用 (Socket多线程实现)

    命令行界面即在Eclipe控制台输入数据. 服务器端包含多个线程,每个Socket对应一条线程,该线程负责读取对应输入流的数据(从客户端发送过来的数据),并将读到的数据向每个Socket输出流发送一遍 ...

  6. LeetCode之“链表”:Remove Nth Node From End of List

    题目链接 题目要求: Given a linked list, remove the nth node from the end of list and return its head. For ex ...

  7. C++中重载、覆盖与隐藏的区别(转)

    本文摘自林锐博士的<高质量C++/C编程指南>. 成员函数的重载.覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚概念,否则错误将防不胜防. 1.重载与覆盖 成员函数被重 ...

  8. 苹果新的编程语言 Swift 语言进阶(二)--基本数据类型

    一  .   常量和变量 Swift语言 对常量和变量的声明进行了明确的区分 Swift语言的常量类型比C 语言的constants类型更加强大,语义更加明确. 常量和变量的区别是常量在设置或初始化后 ...

  9. obj-c编程14:Cocoa和Cocoa Touch简介

    这一篇篇幅相对少很多,几乎没有代码,全部都要靠本猫的语言组织能力啊!Cocoa框架在前面讲解F库时曾简单做过介绍,现在再具体说一说喽.各位童鞋是否已经发现鸟,前面所写的所有代码都是基于终端(或称之为c ...

  10. The 3rd tip of DB QueryAnalyzer

     The 3rd tip of DB Query Analyzer Ma Genfeng (Guangdong Unitoll Services incorporated, Guangzhou 510 ...