不使用他人jar包情况下优雅的进行dubbo调用详解
作者:spider集控团队 发布时间:2022-04-20 11:43:46
标签:jar,包,调用,dubbo
1、正常dubbo调用流程
引入dubbo依赖
引入他人提供的clinet依赖包;
配置相同的注册中心,使用@Reference注解注入对应的service接口(注意是Reference是dubbo包下的,不是spring那个)
2、如果想在不引用他人jar包的情况下如何调用呢?
dubbo泛化调用-dubbo原生支持的优雅方法
使用场景:
消费者不希望引入生产者提供的clinet依赖; 例如:消费者是一个基础服务,需要调用很多生产者的dubbo方法,那他就要引入很多的jar包;
消费者不使用java语言,而是使用其他的语言(例如:Python);
如何使用:
1.需要知道对方方法的全路径名称(interfaceName)
2.如果对方的dubbo有指定的版本号(version)和组(group)要指定一下,不然有很大可能会调用不通
3.要知道对方的注册中心地址和连接方式(如果是在同一个zk注册中心就更好了)
//1.获取泛化对象
private GenericService getGenericService(String interfaceName, String version, String group) {
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
// set application
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setId(APPLICATION_ID);
applicationConfig.setName(APPLICATION_ID);
reference.setApplication(applicationConfig);
// 通过zookeeper连接
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(zkAddress);
registryConfig.setProtocol(ZOOKEEPER);
registryConfig.setCheck(false);
reference.setRegistry(registryConfig);
// set timeout
reference.setTimeout(syncForwardTimeout);
// set retry times
reference.setRetries(syncRetries);
// set check
reference.setCheck(false);
// set generic
reference.setGeneric(true);
// set interface version
if (version != null && version.length() != 0) {
reference.setVersion(version);
}
// set interface name
reference.setInterface(interfaceName);
// set service id
reference.setId(interfaceName);
// set dubbo protocol
reference.setProtocol(DUBBO);
//
if (group != null && group.length() != 0) {
reference.setGroup(group);
}
// 从zookeeper获取缓存,从缓存中获取泛化
return ReferenceConfigCache.getCache().get(reference);
}
//2.泛化调用入参处理
```
private ResponseDataDto<R> invoke(GenericService genericService, UpDataReqDto upDataReqDto, String method) {
String[] paramTypes = new String[1];
Object[] paramValues = new Object[1];
int i = 0;
paramTypes[i] = upDataReqDto.getClass().getTypeName();
paramValues[i] = upDataReqDto;
Object object = genericService.$invoke(method, paramTypes, paramValues);
return JSON.parseObject(JSON.toJSONString(object), new TypeReference<ResponseDataDto<R>>(){});
}
```
实现原理:
泛化调用的实现主要涉及两个filter
1. com.alibaba.dubbo.rpc.filter.GenericFilter
2. com.alibaba.dubbo.rpc.filter.GenericImplFilter
泛化调用的流程:
调用 <-> GenericImplFilter <-> 网络(RPC) <-> GenericFilter <-> 服务实现
泛化调用的核心源码:
GenericImplFilter:
```
//判断是不是泛化调用
if (isCallingGenericImpl(generic, invocation)) {
RpcInvocation invocation2 = new RpcInvocation(invocation);
/**
* Mark this invocation as a generic impl call, this value will be removed automatically before passing on the wire.
* See {@link RpcUtils#sieveUnnecessaryAttachments(Invocation)}
*/
invocation2.put(GENERIC_IMPL_MARKER, true);
String methodName = invocation2.getMethodName();
Class<?>[] parameterTypes = invocation2.getParameterTypes();
Object[] arguments = invocation2.getArguments();
String[] types = new String[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
types[i] = ReflectUtils.getName(parameterTypes[i]);
}
Object[] args;
if (ProtocolUtils.isBeanGenericSerialization(generic)) {
args = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
args[i] = JavaBeanSerializeUtil.serialize(arguments[i], JavaBeanAccessor.METHOD);
}
} else {
args = PojoUtils.generalize(arguments);
}
if (RpcUtils.isReturnTypeFuture(invocation)) {
invocation2.setMethodName($INVOKE_ASYNC);
} else {
invocation2.setMethodName($INVOKE);
}
invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES);
invocation2.setParameterTypesDesc(GENERIC_PARAMETER_DESC);
invocation2.setArguments(new Object[]{methodName, types, args});
return invoker.invoke(invocation2);
}
// 普通服务进行通用调用
else if (isMakingGenericCall(generic, invocation)) {
Object[] args = (Object[]) invocation.getArguments()[2];
if (ProtocolUtils.isJavaGenericSerialization(generic)) {
for (Object arg : args) {
if (byte[].class != arg.getClass()) {
error(generic, byte[].class.getName(), arg.getClass().getName());
}
}
} else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
for (Object arg : args) {
if (!(arg instanceof JavaBeanDescriptor)) {
error(generic, JavaBeanDescriptor.class.getName(), arg.getClass().getName());
}
}
}
invocation.setAttachment(
GENERIC_KEY, invoker.getUrl().getParameter(GENERIC_KEY));
}
GenericFilter:
if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
&& inv.getArguments() != null
&& inv.getArguments().length == 3
&& !GenericService.class.isAssignableFrom(invoker.getInterface())){
.......泛化调用处理逻辑......
}
3、总结
从源码设计来看泛化调用提供了在没有接口依赖的情况下进行调用的解决方案;
从扩展上来看泛化调用的侵入性不强,可以很好的用于框架扩展;
来源:https://juejin.cn/post/7148277888259719199


猜你喜欢
- Apache的POI项目可以用来处理MS Office文档,codeplex上还有一个它的.net版本。POI项目可创建和维护操作各种基于O
- 本文实例讲述了C#实现Xml序列化与反序列化的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// X
- 前言在我的申请下,公司终于购买了一台基于Android12.0的手机,然后我就开心的拿去安装测试了,发现程序崩溃了,于是我这里就写下来,An
- java 解决异常 2 字节的 UTF-8 序列的字节 2 无效的问题
- 经过多次尝试之后,终于找到了开机自动启动App的解决方法开机后会停留在锁屏页面,且短时间内如果没有进行解锁操作,屏幕会进入休眠状态,所以启动
- 解决项目中表单重复提交的问题,在平常的项目中有以下几种可能出现表单重复提交的情况,比如说:1.由于服务器缓慢或者网络延迟的原因,重复点击提交
- Android的闹钟实现机制, 需要调用AlarmManager.set()将闹铃时间记录到系统中,当闹铃时间到后,系统会给应用程序发送广播
- 本文实例讲述了C#使用foreach语句遍历二维数组的方法。分享给大家供大家参考。具体分析如下:如果通过for语句循环遍历二维数组需要两重循
- MyBatis Generator简介MyBatis Generator(MBG)是MyBatis MyBatis 和iBATIS的代码生成
- 多进程如果需要的时候,app可以创建多进程。在进程里面各类组件元素的清单文件条目 、 、 和— 均支持 android:process 属性
- 简介MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)
- 目录1、对于A、B两种排队方式,说法正确的是2、Inter-process communication (IPC) is the trans
- 本文实例为大家分享了OpenCV+Qt实现图像处理操作的具体代码,供大家参考,具体内容如下一、目标Qt界面实现 雪花屏 高斯模糊 中值滤波
- 先给大家展示效果图,如果感觉还不错,请参考实例代码效果图如下所示:具体代码如下:private void initData() { Bmob
- System.getProperty()的作用及使用最近在看一些代码时,很多地方都用到了System.getProperty()、Syste
- 快速普及1、mybatis是什么 mybatis是一个支持普通SQL查询,存储过
- 基本布局演示1. 定义包含GridView 的 main.xmk<?xml version="1.0" encod
- 微信支付流程都是我自己工作中开发的,亲测可用,不喜勿喷。controller中我是这么写的,你们需要根据自己的业务需求改动。Response
- Java压缩文件与解压缩zip文件在日常的使用中经常会使用到像WinRAR或WinZIP这样的压缩文件,通过这些软件可以把一个很大的文件进行
- 引言前面在学习协程启动方式的时候在launch的源码中有一个返回值是Job,async的返回Deferred也是实现了Job,那么而也就是说