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. Spark使用Java读取mysql数据和保存数据到mysql

    原文引自:http://blog.csdn.net/fengzhimohan/article/details/78471952 项目应用需要利用Spark读取mysql数据进行数据分析,然后将分析结果 ...

  2. idea的spring配置

    开始使用idea,开始的时候把相关的插件都禁用了,导致在建项目和configuration的时候不出现spring相关字样 到plugins中找到installed的插件,查看spring boot ...

  3. 2018-8-10-win10-uwp-ping

    title author date CreateTime categories win10 uwp ping lindexi 2018-08-10 19:17:19 +0800 2018-2-13 1 ...

  4. 2018-2-13-win10-安装Mpi

    title author date CreateTime categories win10 安装Mpi lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17:23: ...

  5. 更新view是可以update到表的

    视图不是表,视图里面的数据是通过sql语句去表中查询得到的.当表中的数据发送更改之后,视图里的数据也会发生相应的更改.所以我么一般有两种方式更新视图里面的数据:一是更新表中的数据,从而间接地更新视图中 ...

  6. k8s集群搭建之一:基础环境

    一按照kubernetes对软件和硬件的要求: 二准备的主机系统以及ip配置 角色 系统 IP k8s-master centos7.4 192.168.137.66 k8s-node1 centos ...

  7. go导入包

    go导入包 go有很多内置的函数,例如println,不需要引用即可使用.但是如果不借助go的标准库或者第三方库,我们能做的事情有限.在go中,使用关键字import在代码中导入一个包并使用. 修改我 ...

  8. delphi 给程序加托盘图标

    一些程序运行时,会在桌面的右下角显示一个图标(任务栏的右边),这类图标称为 托盘.托盘是一个PNotifyIconDataA类型的结构,要增加托盘图标其实就是对结构PNotifyIconDataA的操 ...

  9. word文档操作

    1.如何把word文档修改的地方标记出来   :  https://zhidao.baidu.com/question/73648149.html 2.word 的几种 视图:https://zhid ...

  10. mysql 审核

    https://javinjunfeng.top/technicalstack/database/43