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

  • 相关阅读:
    9.11 eventbus
    9.10,,,实现new instanceof apply call 高阶函数,偏函数,柯里化
    9.9 promise实现 写完了传到gitee上面了,这里这个不完整
    9.5cors配置代码
    9.5 jsonp 实现
    9.5 http tcp https总结
    9.3 es6 class一部分 and es5 class 发布订阅
    8.30 cookie session token jwt
    8.30vue响应式原理
    warning: LF will be replaced by CRLF in renard-wx/project.config.json. The file will have its original line endings in your working directory
  • 原文地址:https://www.cnblogs.com/stateis0/p/9007591.html
Copyright © 2011-2022 走看看