现在有一种业务场景:

(1)业务方B调用任务系统A,提交一个任务,由A保证任务尽可能的被执行成功(系统A自带幂等、重试),在A完成任务的执行后将执行情况同步回调通知B应用;

(2)因此,B应用在提交任务时需要把自己的回调地址作为参数传递给A,这个参数被定义为dubbo接口的全路径+方法名+分组+版本号;

(3)系统A不可能提前知晓这个dubbo接口并注册对应的consumer,因此只能通过dubbo的「泛化调用」方式调用业务方B的dubbo接口,即Dubbo的调用方,在不引入服务接口类的情况下,远程调用其他Dubbo服务;

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

下面给出代码示例;

(1)核心方法

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.internet.bocfg.audit.client.model.AuditFlowCallbackRequest;
import com.internet.bocfg.audit.client.model.AuditFlowCallbackResponse;
import com.internet.bocfg.audit.constant.AuditConstants;
import com.internet.bocfg.audit.exception.AuditBusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.utils.ReferenceConfigCache;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Map;/*** @author Akira* @description dubbo泛化调用服务* @date 2022/8/28*/
@Slf4j
@Service
public class DubboGenericService {/*** 缓存已经注册过的GenericService*/private static final Map<String, GenericService> stubCache = Maps.newConcurrentMap();private final ApplicationConfig applicationConfig = new ApplicationConfig("bocfg-audit");@Resource(name = "myRegistryConfig")private RegistryConfig registryConfig;/*** (泛化)远程调用** @param serviceName 接口路径* @param methodName  方法名* @param group       分组* @param version     版本* @param request     自定义的dubbo接口参数*/private void remoteInvoke(String serviceName, String methodName, String group, String version,AuditFlowCallbackRequest request) {try {// 先尝试从缓存中拿GenericService 设置缓存的原因:ReferenceConfig实例很重,封装了与注册中心的连接以及与provider的连接,需要缓存,否则重复生成ReferenceConfig可能造成性能问题并且会有内存和连接泄漏String stubKey = stubKey(serviceName, methodName, version);GenericService genericService = stubCache.get(stubKey);// 未取到则准备初始化当前GenericServiceif (genericService == null) {ReferenceConfig<GenericService> reference = new ReferenceConfig<>();// 连接相关的配置,包括:zk地址、应用名、协议等reference.setApplication(applicationConfig);reference.setRegistry(registryConfig);// 调用相关的配置,包括:声明为泛化接口、不检查状态、负载均衡方式、超时时间等reference.setGeneric(true);reference.setLoadbalance("roundrobin");reference.setCheck(false);reference.setTimeout(AuditConstants.AUDIT_CALLBACK_DEFALUT_TIMEOUT);// 调用目标provider相关的配置,包括:接口、group、version、reference.setInterface(serviceName);reference.setGroup(StringUtils.isBlank(group) ? AuditConstants.AUDIT_CALLBACK_DEFALUT_GROUP : group);reference.setVersion(StringUtils.isBlank(version) ? AuditConstants.AUDIT_CALLBACK_DEFALUT_VERSION : version);// 这里优先使用dubbo内置的简单缓存工具类进行缓存,若没有则放入自己定义的缓存stubCache中ReferenceConfigCache cache = ReferenceConfigCache.getCache();genericService = cache.get(reference);if (genericService != null) {stubCache.putIfAbsent(stubKey, genericService);}genericService = stubCache.get(stubKey);}// 至此,拿到了dubbo接口的genericServiceif (genericService == null) {throw new IllegalStateException("No provider available: " + stubKey);}// 泛化调用的参数:方法名、方法参数类型全路径、方法参数String[] parameterTypes = new String[]{AuditConstants.AUDIT_CALLBACK_REQUEST_CLASSNAME};Object[] args = new Object[]{request};Object result = genericService.$invoke(methodName, parameterTypes, args);if (result != null) {// 泛化调用返参为Object类型,这里做一个参数转换AuditFlowCallbackResponse callbackResponse = JSON.parseObject(JSON.toJSONString(result), AuditFlowCallbackResponse.class);if (!callbackResponse.isSuccess()) {log.warn("callbackResponse fail. serviceName={} methodName={} version={} request={} return={}", serviceName, methodName, version, JSON.toJSONString(request), JSON.toJSONString(callbackResponse));throw new AuditBusinessException("auditCallback fail:" + callbackResponse.getMsg());}}} catch (Throwable e) {log.error("dubbo remoteInvoke fail. serviceName={} methodName={} version={} auditFlowCallbackRequest={}", serviceName, methodName, version, JSON.toJSONString(request));throw e;}}/*** 拼接dubbo的GenericService缓存stubCache(map)中的存根key*/private String stubKey(String serviceName, String method, String version) {return serviceName + "$" + method + "$" +(StringUtils.isBlank(version) ? AuditConstants.AUDIT_CALLBACK_DEFALUT_VERSION : version);}}

(2)RegistryConfig配置

import com.internet.vivocfg.client.ConfigManager;
import org.apache.dubbo.config.RegistryConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class PropertyConfig {@Bean("myRegistryConfig")public RegistryConfig imExchangeConfig() {RegistryConfig registryConfig = null;registryConfig = new RegistryConfig(ConfigManager.get("dubbo.zk.registry.address"));registryConfig.setProtocol("zookeeper");registryConfig.setClient("curator");return registryConfig;}
}

参考:

使用泛化调用 | Apache Dubbo

dubbo实战之“泛化调用”探索 - 博客园

代码技巧——dubbo泛化调用相关推荐

  1. 接口测试-dubbo泛化调用

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

  2. Dubbo泛化调用处理序列化问题

    知其然要知其所以然,刚好趁这个机会把博客重新捡起来. 之前项目的目的是处理dubbo泛化调用的返回值,处理LocalDateTim,LocalDate,LocalTime.转换为时间戳. 一.如何泛化 ...

  3. Dubbo 泛化调用

    dubbo 泛化调用 含义 使用 含义 官方说的文邹邹的,不太懂.按我的理解,就是可以通过指定某个接口的全限定名和方法名,调用远程有提供该方法的服务. 通过上篇文章Dubbo入门,我们可以知道作为服务 ...

  4. dubbo泛化调用原理

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

  5. Dubbo笔记 ⑱ :泛化调用 泛化实现

    文章目录 一.前言 二.泛化调用与泛化实现 1. 泛化调用 2. 泛化实现 三.源码实现 1. GenericImplFilter 2. GenericFilter 四.总结 一.前言 本系列为个人D ...

  6. dubbo的调用原理及泛化调用

    简单介绍 dubbo是阿里开源出来的一个rpc框架,主要是用于微服务分布式项目的远程调用,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现,下面是调用的原理图: ...

  7. Dubbo泛化引用和泛化实现

    开篇 在Dubbo官方文档中关于泛化调用和泛化实现的说明,这里针对文档的案例做一些简单的说明和解释. 例子 // 引用远程服务 // 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 R ...

  8. Dubbo 泛化引用

    前言 大家好,今天开始给大家分享 - Dubbo 专题之 Dubbo 泛化引用.在前一个章节中我们介绍了 Dubbo 中的参数验证以及使用场景.我们在这个章节会继续介绍 Dubbo 泛化引用.那么什么 ...

  9. Apache Dubbo系列:泛化调用

    上一章,我们讲到了Dubbo的线程池策略,本章我们一起探讨,Dubbo如何实现泛化调用的.主要内容包括: 1.什么是泛化调用 2.泛化调用的三种方式 3.如何使用 4.源码分析 推荐阅读: Apach ...

最新文章

  1. SSE2 Intrinsics各函数介绍
  2. 阿提拉公司 java_Atitit  文件上传  架构设计 实现机制 解决方案  实践java php c#.net js javascript  c++ python...
  3. 测试:VS2010的Coded UI Test参考内容列表
  4. 四十年前的 6502 CPU 指令翻译成 JS 代码会是怎样
  5. 理解Session实现原理及安全运用
  6. virtualbox php mac,mac一体机通过Oracle VM VirtualBox装win8.1系统
  7. mfc ctabctrl 双排显示_盐城便宜的开口型双排脚手架生产厂家-斯戴博盘扣脚手架...
  8. C++进阶—— helper function 的设计与实现
  9. Mysql 的 Cascade Restrict
  10. 16.2.4 登录到 SMTP 服务器
  11. PHP 图片无损压缩
  12. 2020年的5种常见骇客行为,你的电脑安全吗?
  13. 过招多家大厂提炼的iOS面试心经(答案版)
  14. IntelliJ IDEA2020安装使用(保姆级)
  15. Processing 案例 | 郭锐文先生的 worms
  16. 图片压缩网址和工具---TinyPNG
  17. revit模型怎么在手机上看_模型的查看和定位-Revit基础教程
  18. 【做题笔记】P2327 [SCOI2005]扫雷
  19. 写给运维新手的十一条 Docker 守则,牢记!
  20. 苹果平板怎么卸载软件_苹果手机需要关闭和卸载一些无用的软件

热门文章

  1. 读后感:《曾国藩》收编 绿营兵
  2. My heart will go on and on
  3. 网红营销到底如何营?如何销?
  4. SnackBar 简单使用
  5. AmazeUI(妹子UI)中CSS组件、JS插件、Web组件的区别
  6. notify()是随机唤醒线程么?
  7. 灵动微MM32F3277可用于替换意法半导体STM32F103
  8. 应用程序开发总结(7)--用折叠数据库字段的方法保存配置
  9. Linux自动切换用户脚本,自动输入用户名密码
  10. 大数据解决方案如何实施