码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-07-27 18:26:39      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:current   result   remoting   服务   send   ddr   pcr   iss   trace   

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();
        while(!future.isDone()){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

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

        AsyncDemoService asyncDemoService = (AsyncDemoService) context.getBean("asyncDemoService");
        asyncDemoService.sayHello("world");

 

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

标签:current   result   remoting   服务   send   ddr   pcr   iss   trace   

原文地址:https://www.cnblogs.com/xkzhangsanx/p/11256043.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!