Apache Dubbo全链路异步怎么实现

本篇内容介绍了“Apache Dubbo全链路异步怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

Dubbo从2.7.0版本开始,升级了对java8的支持,以JUC包下的CompletableFuture为基础,支持所有异步编程接口,解决了2.7.0版本之前异步调用功能使用上的不方便。

Dubbo异步调用也是基于NIO的非阻塞能力实现的,服务消费端不需要启动多个线程即可完成并行调用多个远程服务,其调用流程如下:

Apache Dubbo全链路异步怎么实现  apache 第1张

Dubbo2.7.0之前的弊端

在2.7.0之前,Dubbo的服务消费者异步调用服务提供者的的方式如下:

public interface UserService {    String findUser(String name);}
// 此调用会立即返回nulluserService.findUser(fooId);// 拿到调用的Future引用,当结果返回后,会被通知和设置到此FutureFuture<User> userFuture = RpcContext.getContext().getFuture();userFuture.get();

或者

// 此调用会立即返回nulluserService.findUser(userId);// 拿到Dubbo内置的ResponseFuture并设置回调ResponseFuture future = ((FutureAdapter)RpcContext.getContext().getFuture()).getFuture();future.setCallback(new ResponseCallback() {    @Override    public void done(Object response) {        System.out.print(response);    }    @Override    public void caught(Throwable exception) {        exception.printStackTrace();    }});

我们可以看到,无论从使用方面,还是从代码的整洁度方面,都极不友好,需要进行很多额外的操作才能拿到异步调用后的结果。

Dubbo2.7.0基于CompletableFuture的增强

2.7.0发布后,Dubbo升级到对java8的支持,同时基于CompletableFuture增强了异步调用。2.7.0允许接口返回CompletableFuture,通过这种类型的返回值,我们更容易的实现Consumer、Provider端的异步编程。

Dubbo2.7.0基于CompletableFuture编程的几种方式

方法1、接口直接返回CompletableFuture

基于Dubbo的应用,服务消费者和服务提供者都依赖一个二方SDK,我们可以直接把二方SDK的接口的返回值定义为CompletableFuture类型即可,服务消费端根据这个返回值类型,很方便的进行异步调用。

// 接口定义public interface UsercService {    CompletableFuture<User> findUser(String name);}// Provider端public class UserServiceImpl implements UserService {    public CompletableFuture<User> findUser(String name) {        return CompletableFuture.supplyAsync(() -> {            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                e.printStackTrace();            }            return new User();        });    }}// Consumer端final UserService userService = (AsyncService) context.getBean("userService");CompletableFuture<User> future = userService.findUser("liuli");future.whenComplete((v, t) -> {    if (t != null) {        t.printStackTrace();    } else {       System.out.println("Response: " + v);    }});

方法2、重载原始方法

如果我们不想修改原始方法,我们可以重载原始方法,并将重载后的方法定义为CompletableFuture类型的返回值。

// 定义接口public interface UserService {    // 原始方法    User findUser(String name);    // 为了保证方法级服务治理规则依然有效,建议保持方法名不变: findUser    // 使用default实现,避免给服务端提供者带来额外实现成本    // boolean placeHoler只是为了实现重载而增加,只要Java语法规则允许,你可以使用任何方法重载手段    default CompletableFuture<User> findUser(String name, boolean placeHolder) {      return CompletableFuture.completedFuture(findUser(name));    }}// Provider端public class UserServiceImpl implements UserService {    @Override    public User findUser(String name) {        return new User();    }}// Consumer端UserService userService = (UserService) context.getBean("userService");CompletableFuture<User> future = userService.findUser("liuli");System.out.println("async call ret :" + future.get());

这样一来,服务消费端可以直接调用重载后的findUser方法即可。

方法3、基于AsyncContext实现异步调用

// 接口定义public interface UserService {    User findUser(String name);}// Provider端public class UserServiceImpl implements UsercService {    public User findUser(String name) {        final AsyncContext asyncContext = RpcContext.startAsync();        // 耗时方法在线程中执行        new Thread(() -> {            User user = new User();            // 返回结果            asyncContext.write(user);        }).start();        return null;    }}// Consumer端UserService userService = (UserService) context.getBean("userService");System.out.println(userService.findUser("liuli"));

在方法体中通过RpcContext.startAsync()开启异步,然后耗时业务在新线程中异步执行,然后执行的结果通过asynvContext.write方法写回,方法直接返回null。

“Apache Dubbo全链路异步怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注蜗牛博客网站,小编将为大家输出更多高质量的实用文章!

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

评论

有免费节点资源,我们会通知你!加入纸飞机订阅群

×
天气预报查看日历分享网页手机扫码留言评论电报频道链接