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使用
网关调用的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);
对于一个项目要大量调用其他平台,如移动网关(开放平台这样的)。这时候如果还是按照以前依赖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]
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树