Dubbo的泛化调用是一个服务A在没有服务B的依赖,包的情况下,只知道服务B的服务名:服务的接口的全限定类名和方法名,以及参数,实现服务A调用服务B。

原文链接:http://blog.qiyuan.run/archives/dubbo泛化调用

方案一

服务A定义接口,服务B实现该接口,意味着是服务B需要服务A的依赖,是满足泛化调用的条件的,以下是具体的实现。

1,服务A接口定义

public interface SomethingService {
String getSomethingById(Integer id)
}

2,服务B实现接口

2.1,依赖引入

服务B肯定是需要服务A的依赖的,不然没法找到这个interface去实现。

引入服务A的坐标即可。

2.2,实现接口
@Slf4j
@Service
@DubboService(protocol = "dubbo")
public interface MyBusinessServiceImpl implements SomethingService {
String getSomethingById(Integer id) {
Object result = xxxxMapper.getSomethingById(id);
return result.toString();
}
}

3,服务A定义GenericService

@Configuration
public class SpotterReferenceConfig extends ReferenceConfig<GenericService> {
ReferenceConfig<GenericService> referenceConfig = new ReferenceConfig<>();
@Bean
public GenericService getReferenceConfig(){
referenceConfig.setRegistry(new RegistryConfig("这里填写注册中心地址"));
referenceConfig.setInterface("run.qiyuan.generic.SomethingService");//这里填写服务A定义的接口的全限定类名
referenceConfig.setGeneric("true");//必须设置为true,才能进行泛化
return referenceConfig.get();
}
}

4,如何使用

这里如何使用,肯定是服务服务A如何去调用服务B的实现。

@Autowired
private GenericService genericService; Object result = genericService.$invoke(
"getSomethingById",//这里是服务方法名
new String[]{"java.lang.Integer"},//这里是方法参数的类型
new Object[]{101});//这里是方法参数值
System.out.println(result);//这里的返回值定义为Object,但是实际返回值的类型都是Map集合

5,总结

该方案适合固定的服务接口,方法,参数等,这种方案会发现注册中心中,关于提供服务SomethingService的都是服务A,虽说实现是服务B实现的。这样就会出现很不好的地方,如果有服务A需要调用不同的服务B,服务C,服务D等,这些服务都去实现该接口,就会在注册中心上发现该服务下面有多个实例,每个实例对应一个服务,服务发起调用的时候,没有传递关于到底是调用哪个实例的参数,就会出现混乱。

方案二

根据方案二的局限性,这里提出一种更加便利,可以说是更加泛化的一种方案。

假设有三个服务,【消费方:服务A】,【提供方:服务B,服务C】,需求是服务A可能会去调用服务B,C的服务,如何实现,且看下面。

1,服务B、C定义接口,实现接口

这里和方案一不同的是,提供方的接口和实现都是自己维护的,这个和平常的开发没有区别,例如:

接口定义

public interface UserService{
Integer addUser(User user);
User getUserById(Integer id);
}

接口实现

public interface UserServiceImpl implements UserService{
Integer addUser(User user){
return userMapper.addUser(user);
}
User getUserById(Integer id){
//////
}
}

2,服务A定义泛化调用工具类

public class DubboGenericInvoke {
private static Map<String, ReferenceConfig<GenericService>> referenceConfigMap = new ConcurrentHashMap<>();
public static Object invoke(String tag,String interfaceClass, String methodName, String[] paramTypes, Object[] params) {
ReferenceConfig<GenericService> referenceConfig;
String key = interfaceClass+"---"+tag;
try {
referenceConfig = referenceConfigMap.get(key);
if (referenceConfig == null) {
referenceConfig = new ReferenceConfig<>();
RegistryConfig registry = new RegistryConfig("这里填写注册中心地址");
referenceConfig.setRegistry(registry);
referenceConfig.setRetries(4);//重试次数
ConsumerConfig consumerConfig = new ConsumerConfig();
referenceConfig.setConsumer(consumerConfig);
referenceConfig.setGeneric(CommonConstants.GENERIC_SERIALIZATION_DEFAULT);
referenceConfig.setInterface(interfaceClass);
referenceConfig.setTimeout(3000);//ms,如果服务方超时时间超过了这里的时间,将进行重试,达到重试次数时,报超时异常。
if(tag.length()!=0){
referenceConfig.setTag(tag);
}
referenceConfig.setCheck(true);
referenceConfigMap.put(key, referenceConfig);
}
GenericService genericService = referenceConfigMap.get(key).get();
Object result = genericService.$invoke(methodName, paramTypes, params);
if (result == null) {
log.info("远程服务结果返回为空,请注意查看远程服务的参数:{}", params);
}
return result;
} catch (GenericException e) {
log.info("发起远程调用失败,错误信息:{}", e.getMessage());
referenceConfigMap.remove(key);
return null; } catch (Exception e) {
log.info("远程服务获取结果失败,错误信息:{}", e.getMessage());
referenceConfigMap.remove(key);
return null;
}
}
}

3,如何使用

服务A服务去使用该工具类呢,直接调用就可以了。

HashMap map = new HashMap();
map.put("userName","一只小Coder");
map.put("passWord","root");
DubboGenericInvoke.invoke("your_tag",//表示需要调用哪个实例的服务,通过Dubbo的tag属性来区分
"run.qiyuan.service.UserService",//需要调用的服务的全限定类名
"addUser", //方法
new Object[]{"run.qiyuan.model.User"},//参数类型,不仅支持java的基本数据类型,同时支持自定义类型
new Object[]{map});//如果是基本数据类型,组装成Map集合就好了

通过以上代码可以发现,可以实现对同一个服务,不同实例进行调用;可以实现对不同的服务的调用,传递的interfaceClass也都是我们自己维护的。缺点就是第一次调用一个服务的时候有点慢,因为要去注册,我看网上有很多事通过一个ReferenceCache来存放的,我这里使用的是一个Map集合,都差不多,解决这个问题,可是在项目启动的时候,先去讲可能需要调用的服务都先去调用遍,这样每个服务就在Map集合中了。

两种方案实现Dubbo泛化调用的更多相关文章

  1. Spring Boot 配置文件密码加密两种方案

    Spring Boot 配置文件密码加密两种方案 jasypt 加解密 jasypt 是一个简单易用的加解密Java库,可以快速集成到 Spring 项目中.可以快速集成到 Spring Boot 项 ...

  2. .Net Core下使用RabbitMQ比较完备的两种方案(虽然代码有点惨淡,不过我会完善)

    一.前言     上篇说给大家来写C#和Java的方案,最近工作也比较忙,迟到了一些,我先给大家补上C#的方案,另外如果没看我上篇博客的人最好看一下,否则你可能看的云里雾里的,这里我就不进行具体的方案 ...

  3. dubbo泛化调用 小demo

    前两天刚好有个同事来问是否用过 dubbo泛化 调用,不需要通过指定配置.第一次听到的时候,还是有点懵,但觉得有意思,可以学点东西. 立马百度了,找了demo,这篇比较容易上手(http://www. ...

  4. 详解Grunt插件之LiveReload实现页面自动刷新(两种方案)

    http://www.jb51.net/article/70415.htm    含Grunt系列教程 这篇文章主要通过两种方案详解Grunt插件之LiveReload实现页面自动刷新,需要的朋友可以 ...

  5. Linux下实现秒级定时任务的两种方案

    Linux下实现秒级定时任务的两种方案(Crontab 每秒运行): 第一种方案,当然是写一个后台运行的脚本一直循环,然后每次循环sleep一段时间. while true ;do command s ...

  6. [转载]Java操作Excel文件的两种方案

    微软在桌面系统上的成功,令我们不得不大量使用它的办公产品,如:Word,Excel.时至今日,它的源代码仍然不公开已封锁了我们的进一步应用和开发.在我们实际开发企业办公系统的过程中,常常有客户这样子要 ...

  7. 比较好用的移动端适配的两种方案及flexible和px2rem-loader在webpack下的配置

    移动端适配,目前自己常用的两种 方案,参考以下两篇好文 方案一:使用lib-flexible包 https://www.w3cplus.com/mobile/lib-flexible-for-html ...

  8. Git--gitLab远程仓库分支代码回退的两种方案

    事由:作为仓库的master,一时老眼昏花,把同事说的不合并看成了合并,直接合并了. 解决方法: 一.粗鲁的代码回退--直接在远程仓库合并 1. 在gitLab远程仓库中,基于想回退的代码的节点(co ...

  9. kettle 多表全删全插同步数据 两种方案

    背景: 接到上级指示,要从外网某库把数据全部导入到内网,数据每天更新一次即可,大约几百万条数据,两个库结构一样,mysql的,两台数据库所在服务器都是windows server的,写个java接口实 ...

  10. C#将Word转换成PDF方法总结(基于Office和WPS两种方案)

    有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有的格式和图片.一个比较好的办法就是将word转换成pdf,然 ...

随机推荐

  1. Spire.Cloud 私有化部署教程(三) - Windows 系统

    本教程主要介绍如何在 Windows 系统上实现 Spire.Cloud 私有化部署. 详细步骤如下: 一.安装依赖 我们的私有部署的依赖有 Nodejs.MySQL.Redis 和 RabbitMQ ...

  2. .NET使用StackTrace获取方法调用者信息

    前言 在日常工作中,偶尔需要调查一些诡异的问题,而业务代码经过长时间的演化,很可能已经变得错综复杂,流程.分支众多,如果能在关键方法的日志里添加上调用者的信息,将对定位问题非常有帮助. 介绍 Stac ...

  3. Docker_删除所有容器

    删除所有容器 docker rm `docker ps -aq`

  4. Q准则涡识别方法

    Q准则(Q Criterion)在涡识别中计算效率高,效果也不错,是一种常用的涡提取/识别方法. 了解Q准则需要从速度梯度张量入手,而速度梯度张量可以分解成两部分 \[\frac{\partial u ...

  5. 新建Github仓库并上传本地代码

    按照Github的教程 Adding a local repository to GitHub using Git 1. 创建空的Github仓库 创建远程仓库 ,注意不要勾选Add a README ...

  6. KMP&Z函数详解

    KMP 一些简单的定义: 真前缀:不是整个字符串的前缀 真后缀:不是整个字符串的后缀 当然不可能这么简单的,来个重要的定义 前缀函数: 给定一个长度为\(n\)的字符串\(s\),其 \(前缀函数\) ...

  7. 微服务低代码Serverless平台(星链)的应用实践

    导读 星链是京东科技消金基础研发部研发的一款研发效能提升的工具平台,面向后端服务研发需求,尤其是集成性.场景化.定制化等难度不太高.但比较繁琐的需求,如服务前端的后端(BFF).服务流程编排.异步消息 ...

  8. 记录一下对jdk8后的接口的一些理解

    对于jdk8后的接口,接口中加入了可以定义默认方法和静态方法. 为什么要这样设计呢? 是为了在给接口扩展方法的时候,不会影响已经实现了该接口的类 加入默认方法可以解决:在添加方法的同时,不影响现有的实 ...

  9. 7.nexus版本升级

    nexus-3.14.0升级到3.15.2 首先来看下原来的服务目录: nexus-3.14.0-04 sonatype-work 注意:nexus-3.14.0-04是应用程序包,sonatype- ...

  10. C/C++ 宏定义

    宏定义(无参宏定义和带参宏定义) 宏定义是比较常用的预处理指令,即使用"标识符"来表示"替换列表"中的内容.标识符称为宏名,在预处理过程中,预处理器会把源程序中 ...