zoukankan      html  css  js  c++  java
  • SOFA 源码分析 — 泛化调用

    前言

    通常 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 中会根据枚举值动态获取不同的序列化器和反序列化器,对输出参数和返回值经进行处理。

  • 相关阅读:
    Ubuntu20安装docker
    ubuntu 下mysql 大小写问题
    Tensorflow-常见报错解决方案
    迁移学习(Transfer Learning)
    c#的托管代码和非托管代码的理解
    .net面试题升级版
    ADO.NET知识点
    支持“WeShopDb”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库
    .net 面试题
    6、zookeeper应用场景-分布式唯一ID
  • 原文地址:https://www.cnblogs.com/stateis0/p/9007591.html
Copyright © 2011-2022 走看看