您的位置:首页 > 编程语言 > Java开发

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

2016-07-12 09:31 483 查看
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)
4000
{
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}}文章信息。如有其他相关疑问可以相互讨论。[/code] 
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dubbo 泛化 java