dubbo默认使用同步的方式调用。但在有些特殊的场景下,我们可能希望异步调用dubbo接口,从而避免不必要的等待时间,这时候我们就需要用到异步。那么dubbo的异步是如何实现的呢?下面就来看看这个问题

异步方法配置:

<dubbo:reference cache="lru" id="demoService" interface="com.ping.chen.dubbo.service.DemoService" timeout="5000">
<dubbo:method name="sayHello" async="true"/>
</dubbo:reference>

底层的异步处理实现在DubboInvoker的doInvoke方法中,源码如下:

protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
忽略Attachment设置。。。
try {
// 是否异步执行
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);//是否单向执行
int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);//接口超时时间,默认1秒
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture(null);
return new RpcResult();
} else if (isAsync) {//异步
ResponseFuture future = currentClient.request(inv, timeout);
RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
return new RpcResult();
} else {
RpcContext.getContext().setFuture(null);
return (Result) currentClient.request(inv, timeout).get();
}
} catch (TimeoutException e) {
//异常处理。。。
}
}

可以看到,如果异步执行,会直接返回一个空的RpcResult,然后用户如果需要异步执行结果,可以从RpcContext中的Future中去获取,直接用RpcContext.getContext().getFuture().get();就可以获取到执行结果。那么RpcContext是如何保证当前线程可以拿到执行结果呢?答案是ThreadLocal。我们来看看RpcContext源码如下:

public class RpcContext {

	private static final ThreadLocal<RpcContext> LOCAL = new ThreadLocal<RpcContext>() {
@Override
protected RpcContext initialValue() {
return new RpcContext();
}
};
public static RpcContext getContext() {
return LOCAL.get();
}
。。。。。。
}

可以看到RpcContext 内部是使用ThreadLocal来实现的。

异步可能遇到的坑

上面这种配置有一个坑,可能你会像下面这样使用异步:

@RestController
public class DemoController {
@Reference(timeout = 5000)
DemoProvider demoProvider; @RequestMapping("/demo")
public void demo() throws ExecutionException, InterruptedException {
demoProvider.sayHello("world");
System.out.println(">>>>>>>>>>" + RpcContext.getContext().getFuture().get());
}
}

然后请求demo接口的时候,很不幸,你将会收到一个NullPointException,这因为我们只在消费者端配置了异步执行,但服务端执行的时候是同步的,所以我们从RpcContext中获取到的Future是空的,正确的异步配置应该是:

直接去掉消费者端的

<dubbo:method name="sayHello" async="true"/>

配置,然后在服务提供者端做如下配置:

<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.ping.chen.dubbo.provider.DemoProvider" ref="demoProvider" >
<dubbo:method name="sayHello" async="true"/>
</dubbo:service>

如此,便可以实现异步了

dubbo入门之异步调用的更多相关文章

  1. 使用rabbit mq.模拟dubbo,使MQ异步调用代码写起来像是同步方法.

    最近在改造老系统,遇到了需要使用rabbitMq的场景.在以前使用的过程中需要在发送端和消费端各种配置,感觉比较麻烦,然后突然想到了dubbo中@Reference注解的形式,可不可以做一个类似的架子 ...

  2. Dubbo中CompletableFuture异步调用

    使用Future实现异步调用,对于无需获取返回值的操作来说不存在问题,但消费者若需要获取到最终的异步执行结果,则会出现问题:消费者在使用Future的get()方法获取返回值时被阻塞.为了解决这个问题 ...

  3. Dubbo学习笔记4:服务消费端泛化调用与异步调用

    本文借用dubbo.learn的Dubbo API方式来解释原理. 服务消费端泛化调用 前面我们讲解到,基于Spring和基于Dubbo API方式搭建简单的分布式系统时,服务消费端引入了一个SDK二 ...

  4. dubbo同步/异步调用的方式

    我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制:基于这种机制,Dubbo 实现了以下几种调用方式: 同步调用(默认) 异步调用 参数回调 事件通知 同步 ...

  5. 9.4 dubbo异步调用原理

    9.1 客户端发起请求源码.9.2 服务端接收请求消息并发送响应消息源码.9.3 客户端接收响应信息(异步转同步的实现) 分析了dubbo同步调用的源码,现在来看一下dubbo异步调用. 一.使用方式 ...

  6. 限时购校验小工具&dubbo异步调用实现限

    本文来自网易云社区 作者:张伟 背景 限时购是网易考拉目前比较常用的促销形式,但是前期创建一个限时购活动时需要各个BU按照指定的Excel格式进行选品提报,为了保证提报数据准确,运营需要人肉校验很多信 ...

  7. dubbo之异步调用

    异步调用 基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小. 在 consumer.xml 中配置: <dubbo:reference ...

  8. dubbo同步调用、异步调用和是否返回结果源码分析和实例

    0. dubbo同步调用.异步调用和是否返回结果配置 (1)dubbo默认为同步调用,并且有返回结果. (2)dubbo异步调用配置,设置 async="true",异步调用可以提 ...

  9. Dubbo消费者异步调用Future使用

    Dubbo的四大组件工作原理图,其中消费者调用提供者采用的是同步调用方式.消费者对于提供者的调用,也可以采用异步方式进行调用.异步调用一般应用于提供者提供的是耗时性IO服务 一.Future异步执行原 ...

随机推荐

  1. 升级python后yum命令出错

    执行yum命令报错: yum list Loaded plugins: fastestmirror base | 3.6 kB 00:00:00 epel | 5.3 kB 00:00:00 extr ...

  2. 群晖NAS被攻击

    上周给新员工办理入职的时候,因为我们有自己的NAS系统,给他们建账号的时候,突然发现群晖无法登陆,很奇怪. 然后查看群晖系统,发现网络能Ping 通,但是群晖管理界面无法打开,一开始以为机房天热,硬盘 ...

  3. STL_Algorithm

    #include <algorithm> #include <cstdio> using namespace std; /*虽然最后一个排列没有下一个排列,用next_perm ...

  4. webpack起的项目怎么用手机访问?

    默认情况下 webpack-dev-server只能通过 localhost 访问 如果需要通过 ip 地址访问,修改 npm 配置文件中的 scripts 属性中对应的启动脚本 例如 start 或 ...

  5. wordpress 添加 显示磁盘剩余空间百分比的插件

    在 wp-content/plugins 文件夹下 我取的文件名是: folder-sizes-dashboard-widget.php 在仪表盘 可以看到 Folder Sizes 标题的Box & ...

  6. linux crontab 计划任务脚本

    在LINUX中你应该先输入crontab -e,然后就会有个vi编辑界面,再输入0 3 * * 1 /clearigame2内容到里面 :wq 保存退出. 在LINUX中,周期执行的任务一般由cron ...

  7. github fork代码后提交

    点击他人github上的fork 在自己的Github上将代码拷贝下来 git clone 在本地修改代码后创建分支 git checkout -b work master(work为新建的特性分支, ...

  8. 开启.NET Core 3时代,DevExpress v19.2.5带你全新启航

    DevExpress Universal Subscription(又名DevExpress宇宙版或DXperience Universal Suite)是全球使用广泛的.NET用户界面控件套包,De ...

  9. 删除Excel空列

    /// <summary> /// 删除Excel空列 /// </summary> /// <param name="excelPath">E ...

  10. leetcood学习笔记-27-移除元素

    题目: 第一次提交: class Solution: def removeElement(self, nums, val: int) -> int: for i in range(len(num ...