这篇文章主要介绍“怎么使用Dubbo异步处理”,在日常操作中,相信很多人在怎么使用Dubbo异步处理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用Dubbo异步处理”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
异步调用
我们平常大部分都是使用 Dubbo 的同步调用,即调用 Dubbo 请求之后,调用线程将会阻塞,直到服务提供者返回结果。
那相反,Dubbo 异步调用就不会阻塞调用线程,那么在服务提供者返回结果这段时间,我们就可以执行其他业务逻辑。
下面我们从代码示例,来学习一下如何使用 Dubbo 异步调用。
PS:下面例子 Dubbo 版本为 2.7。
第一种方式
Dubbo 异步调用是针对方法级别,所以我们需要对引用接口中指定方法做一些专门的配置。
异步调用配置其实与普通 xml服务引用配置类似,只不过我们还需要增加一个 dubbo:method将指定方法配置成异步调用。
示例 xml 配置如下:
<dubbo:reference id="asyncService" interface="org.apache.dubbo.samples.governance.api.AsyncService"> <dubbo:method name="sayHello" async="true" /> </dubbo:reference>
服务引用配置完成之后,此时如果直接调用这个方法,将会立即返回 null,内部将会异步执行服务端调用逻辑。
// 此调用会立即返回null String world = asyncService.sayHello("world");
// 画个时序图
如果我们需要获取服务提供者返回的结果,那么此时需要借助 RpcContext。这个类是 Dubbo 中专门用于保存 「RPC」 调用过程中一些关键信息。
因此我们可以借助这个类可以获取到 「RPC」 很多信息,这次我们主要使用下面的方法获取 CompletableFuture。
RpcContext.getContext().getCompletableFuture()
CompletableFuture 是 JDK1.8 之后提供的异步任务增强类,我们可以直接调用其 get 方法直接获取返回结果。
// 此调用会立即返回null String world = asyncService.sayHello("world"); // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture(); helloFuture.get();
这里需要注意一点。调用get 方法之后,线程就会被阻塞,「直到服务端返回结果或者服务调用超时」。
另外如果不想线程被阻塞,我们可以使用 whenComplete,添加回调方法,然后异步处理返回结果。
// 此调用会立即返回null String world = asyncService.sayHello("world"); // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture(); // 为Future添加回调 helloFuture.whenComplete((retValue, exception) -> { if (exception == null) { System.out.println("return value: " + retValue); } else { exception.printStackTrace(); } });
从上面的例子我们可以看到, Dubbo 消费端异步调用借助了JDK 提供的 CompletableFuture,这个类非常强大,提供的方法也非常多。
小黑哥之前写过一篇文章,比较完整的介绍了 CompletableFuture的用法,感兴趣可以深入学习一下。
// TODO 文章
上面的方式我们使用 xml引用服务,不过现在很多同学应该直接使用 Dubbo 注解引用服务。
如果想直接使用注解方式,其实也非常简单,只要使用 @Method注解即可。
配置方法如下:
@Reference(interfaceClass = AsyncService.class, timeout = 1000, methods = {@Method(name = "sayHello", async = true)}) private AsyncService asyncService;
第二种方式
第一种方式我们还需要额外修改 Dubbo 相关配置,相对来说比较繁琐。那第二种方式就不需要做额外配置了,它只要使用 RpcContext#asyncCall就可以直接完成异步调用。
示例代码如下:
// 使用 asyncCall 异步调用 CompletableFuture<String> f = RpcContext.getContext().asyncCall(() -> asyncService.sayHello("async call request")); // get 将会一直阻塞到服务端返回,或者直到服务调用超时 System.out.println("async call returned: " + f.get()); // 异步调用,不关心服务端返回 RpcContext.getContext().asyncCall(() -> { asyncService.sayHello("one way call request1"); });
这种方式返回依然是 CompletableFuture对象,操作方式就如同第一种方式。
第三种方式
终于到了最后一种方式了,这种方式与上面两种方式都不太一样,其完全不需要借助RpcContext就可以完成,开发流程与普通 Dubbo 服务一样。
首先需要服务提供者事先定义 CompletableFuture 签名的服务:
public interface AsyncService { CompletableFuture<String> sayHello(String name); }
「注意接口的返回类型是 CompletableFuture
服务端接口实现逻辑如下:
public class AsyncServiceImpl implements AsyncService { private static Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class); @Override public CompletableFuture<String> sayHello(String name) { return CompletableFuture.supplyAsync(() -> { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } return "async response from provider."; }); } }
服务端需要使用 CompletableFuture 完成业务逻辑。
消费端这时就不需要借助了 RpcContext,可以直接调用服务提供者。
// 调用直接返回CompletableFuture CompletableFuture<String> future = asyncService.sayHello("async call request"); // 增加回调 future.whenComplete((v, t) -> { if (t != null) { t.printStackTrace(); } else { System.out.println("Response: " + v); } }); // 早于结果输出 System.out.println("Executed before response return.")
这种方式对于调用者来就比较方便,无需引入其他对象,可以像使用同步的方式使用异步调用。
其他参数
上面介绍了三种的 Dubbo 异步调用的使用方式,下面主要介绍一下异步调用涉及其他参数。
sent
我们可以在 dubbo:method 设置:
<dubbo:method name="findFoo" async="true" sent="true" />
也可以在注解中设置:
@Reference(interfaceClass = XXX.class, version = AnnotationConstants.VERSION, timeout = 1000, methods = {@Method(name = "greeting", timeout = 3000, retries = 1, sent = false)})
默认情况下sent=false, Dubbo 将会把消息放入 IO 队列,然后立刻返回。那这时如果宕机,消息就有可能没有发送给服务端。
那如果我们将其设置成 sent=true,Dubbo 将会等待消息发送发出才会返回,否则将会抛出异常。
return
Dubbo 异步调用默认将会创建 Future 对象,然后设置到 RpcContext 中。那我们如果不关心返回值,只想单纯的异步执行,那我们可以配置 return="false",以此减少 Future 对象的创建和管理成本。
<dubbo:method name="findFoo" async="true" return="false" />
到此,关于“怎么使用Dubbo异步处理”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!