dubobo接口的泛化调用(不依赖jar包)

1 篇文章 0 订阅
1 篇文章 0 订阅

1.dubbo泛化调用的应用场景(个人观点)

      对于一个项目要大量调用其他平台,如移动网关(开放平台这样的)。这时候如果还是按照以前依赖jar包的调用方式,项目打包之后将极其的庞大,后期也难以扩展,这时候就需要dubbo泛化的调用方式。

2.dubbo泛化处理过程

关于泛化,dubbo文档这样描述的。

http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E6%B3%9B%E5%8C%96%E5%BC%95%E7%94%A8

泛接口调用方式主要用于客户端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过GenericService调用所有服务实现。

http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E6%B3%9B%E5%8C%96%E5%AE%9E%E7%8E%B0

泛接口实现方式主要用于服务器端没有API接口及模型类元的情况,参数及返回值中的所有POJO均用Map表示,通常用于框架集成,比如:实现一个通用的远程服务Mock框架,可通过实现GenericService接口处理所有服务请求。


总的意思来说,某些环境(通用网关、服务端Mock),dubbo接口和类的参数、返回值的类型可能不能加载。为了这些环境也能调用/实现dubbo服务,dubbo框架会对参数和返回值进行泛化(序列)处理,默认处理为Map表示的字符串。虽然文档没有介绍,实际上,dubbo还支持另外两种泛化处理--nativejava(利用java原生序列化)、bean(序列化为JavaBeanDescriptor)。


dubbo通过filter实现泛化:

调用 <-> GenericImplFilter <->网络<->GenericFilter <-> 服务实现

GenericImplFilter和GenericFilter分别在消费者端和提供者端进行序列化的检查和处理。

3.部分代码的实现

(1)  GenericService使用

private static Cache<String, GenericService> servicesCache= CacheBuilder.newBuilder().expireAfterAccess(
        cacheDubTimes, TimeUnit.SECONDS).maximumSize(200).build();

/**
 * 缓存获取泛化接口
  * @param infAddressDO 接口信息
 * @return 返回泛化接口
 */
public GenericService getServiceByCache(InfAddressDO infAddressDO) {
    log.info("start to get dub getService inf:{}", infAddressDO.getHost());
    StringBuilder serviceKey = new StringBuilder(String.join("", MAPI_KEY_PRE, INF_DUB_KEY, infAddressDO.getHost()));
    log.debug("get dub interface key :{}", serviceKey);

    GenericService service = null;
    try {
        service = servicesCache.get(serviceKey.toString(), new Callable<GenericService>() {
            @Override
            public GenericService call() throws Exception {
                ReferenceConfig<GenericService> referenceConfig = createReferenceConfig(infAddressDO.getHost());
                GenericService genericService = referenceConfig.get();
                servicesCache.put(serviceKey.toString(),genericService);
                return genericService;
            }
        });
    } catch (ExecutionException e) {
       log.error("ExecutionException when get service in servicesCache error:{}",e);
    }
    if (service != null) {
        return service;
    }

    servicesCache.put(serviceKey.toString(), service);
    log.info("return service:{}", service);
    return service;
}
private ReferenceConfig createReferenceConfig(String interfaceName) {

    //接口引用
    ReferenceConfig referenceConfig = new ReferenceConfig<>();
    referenceConfig.setApplication(getApplicationConfig());
    referenceConfig.setRegistry(getRegistryConfig());
    referenceConfig.setConsumer(getConsumerConfig());
    referenceConfig.setInterface(interfaceName);
    referenceConfig.setGeneric(true);

    return referenceConfig;
}

private ApplicationConfig getApplicationConfig() {
    if (APPLICATION != null) {
        return APPLICATION;
    }
    APPLICATION = new ApplicationConfig(dubConfig.getDubApplicationName());
    return APPLICATION;
}

private ConsumerConfig getConsumerConfig() {
    if (CONSUMER != null) {
        return CONSUMER;
    }
    CONSUMER = new ConsumerConfig();
    CONSUMER.setTimeout(dubConfig.getDubTimeout());
    CONSUMER.setRetries(0);
    return CONSUMER;
}

private RegistryConfig getRegistryConfig() {
    if (REGISTRY != null) {
        return REGISTRY;
    }
    REGISTRY = new RegistryConfig(String.join("", "zookeeper://", dubConfig.getDubZookeeperUrl()));
    return REGISTRY;
}
注:以上dubbo接口维护是在配置文件,或者数据库中维护的,动态可配置。
(2) 调用方式
GenericService service = dubUtil.getServiceByCache(addressDO);
Map<String, Object> resMap = (Map<String, Object>) service.$invoke(addressDO.getInfMethod(), parameterTypes, invokeArgs);
4.泛化通用类型性能方面注意

网关调用的dubbo服务的参数和返回值都是通用类型,在网关侧也能加载的。并且,网关侧还需要对返回值进行进一步处理。所以,如果像默认dubbo泛化那样序列化为包含String的Map,那我处理前还需要再反序列化,这比较麻烦(需要确保被反序列化的POJO),性能也不高。


要解决这种问题,可以新增一种泛化类型。

public static final String GENERIC_SERIALIZATION_NOCHANGE      = "nochange";

    public static boolean isGeneric(String generic) {
        return generic != null
            && !"".equals(generic)
            && (Constants.GENERIC_SERIALIZATION_DEFAULT.equalsIgnoreCase(generic)  /* 正常的泛化调用 */
            || Constants.GENERIC_SERIALIZATION_NATIVE_JAVA.equalsIgnoreCase(generic) /* 支持java序列化的流式泛化调用 */
            || Constants.GENERIC_SERIALIZATION_BEAN.equalsIgnoreCase(generic)
            || Constants.GENERIC_SERIALIZATION_NOCHANGE.equalsIgnoreCase(generic));
    }


并且,GenericFilter中发现如果是这种泛化类型,那么不对服务实现的返回值进行序列化处理。

                } else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
                    return new RpcResult(JavaBeanSerializeUtil.serialize(result.getValue(), JavaBeanAccessor.METHOD));
                } else if (ProtocolUtils.isNoChangeGenericSerialization(generic)) {
                    return new RpcResult(result.getValue());

                } else {
                    return new RpcResult(PojoUtils.generalize(result.getValue()));
                }


这样,只要初始化时设置好泛化类型,genericService.$invoke获得的返回值就直接是服务端的值,不是Map等表示的值。

        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
        reference.setApplication(application);
        reference.setRegistries(registries);
        reference.setInterface(serverInterface);
        reference.setGeneric(Constants.GENERIC_SERIALIZATION_NOCHANGE);

注:以上文章参考了 http://my.oschina.net/zhaojy/blog/646662?p={{page}}文章信息。如有其他相关疑问可以相互讨论。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值