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


    0. dubbo同步调用、异步调用和是否返回结果配置

    (1)dubbo默认为同步调用,并且有返回结果。

    (2)dubbo异步调用配置,设置 async="true",异步调用可以提高效率。

    (3)dubbo默认是有返回结果,不需要返回,可以设置return="false",不需要返回值,可以减少等待结果时间。

    1. 源码分析(dubbo版本:2.6.0)

    dubbo自身底层调用是使用netty异步实现的,默认同步调用返回结果,是通过获取ResponseFuture,然后使用ReentrantLock的await使当前线程等待结果,设置返回的。下面是部分核心代码部分:

    com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(Invocation)

        @Override
        protected Result doInvoke(final Invocation invocation) throws Throwable {
            RpcInvocation inv = (RpcInvocation) invocation;
            final String methodName = RpcUtils.getMethodName(invocation);
            inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
            inv.setAttachment(Constants.VERSION_KEY, version);
    
            ExchangeClient currentClient;
            if (clients.length == 1) {
                currentClient = clients[0];
            } else {
                currentClient = clients[index.getAndIncrement() % clients.length];
            }
            try {
                // 获取是否异步配置async
                boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
                // 获取是否需要返回结果配置return
                boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
                // 获取超时配置timeout
                int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
                if (isOneway) {
                    // 不管是否异步,只要不需要返回结果,直接异步调用,设置结果为null
                    boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                    currentClient.send(inv, isSent);
                    RpcContext.getContext().setFuture(null);
                    return new RpcResult();
                } else if (isAsync) {
                    // 如果异步,并且需要返回结果,调用后设置结果future
                    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) {
                throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
            } catch (RemotingException e) {
                throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
            }
        }

    2. 实例

    这里使用dubbo源码自带的例子

    (1)在dubbo-demo-api中定义异步服务

    package com.alibaba.dubbo.demo;
    
    public interface AsyncDemoService {
        String sayHello(String name);
    }

    (2)在dubbo-demo-provider中实现

    package com.alibaba.dubbo.demo.provider;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import com.alibaba.dubbo.demo.AsyncDemoService;
    import com.alibaba.dubbo.rpc.RpcContext;
    
    public class AsyncDemoServiceImpl implements AsyncDemoService{
    
        @Override
        public String sayHello(String name) {
            System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
            return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
        }
    
    }

    (3)在dubbo-demo-provider.xml中配置服务信息

        <bean id="asyncDemoService" class="com.alibaba.dubbo.demo.provider.AsyncDemoServiceImpl"/>
    
    
        <dubbo:service interface="com.alibaba.dubbo.demo.AsyncDemoService" ref="asyncDemoService"/>

    (4)在dubbo-demo-consumer.xml中配置调用服务信息,设置为异步调用async="true" 

        <dubbo:reference id="asyncDemoService" check="false" interface="com.alibaba.dubbo.demo.AsyncDemoService">
            <dubbo:method name="sayHello" async="true"/>
        </dubbo:reference>

    (5)在dubbo-demo-consumer的Consumer类中增加调用

            AsyncDemoService asyncDemoService = (AsyncDemoService) context.getBean("asyncDemoService");
            asyncDemoService.sayHello("world");
            // 通过 1.源码分析 中可以知道异步返回结果放到了RpcContext.getContext()中
            Future<String> future =  RpcContext.getContext().getFuture();

          try {
              String hello = future.get(1, TimeUnit.SECONDS);
              System.out.println(hello);
            } catch (InterruptedException e) {
              e.printStackTrace();
            } catch (ExecutionException e) {
              e.printStackTrace();
            } catch (TimeoutException e) {
              e.printStackTrace();
            }

    (6)不需要返回结果,配置dubbo-demo-consumer.xml 中return="false",同步异步的调用方式一样的,很简单,只需要调用一下就可以继续其他操作,下面是异步的例子。

            AsyncDemoService asyncDemoService = (AsyncDemoService) context.getBean("asyncDemoService");
            asyncDemoService.sayHello("world");
    寻找撬动地球的支点(解决问题的方案),杠杆(Java等编程语言)已经有了。xkzhangsan
  • 相关阅读:
    Beego快速入门
    Ubuntu常用配置
    软件过程改进练习题
    将博客搬至CSDN
    【PTA】04-树4 是否同一棵二叉搜索树
    【PTA】03-树1 树的同构
    【转】面试还搞不懂redis,快看看这40道Redis面试题(含答案和思维导图)
    数据挖掘--聚类算法对比
    数据挖掘--模型挖掘之聚类
    数据挖掘--OPTICS
  • 原文地址:https://www.cnblogs.com/xkzhangsanx/p/11256043.html
Copyright © 2020-2023  润新知