一般情况,consumer发送请求时,创建一个DefaultFuture对象,然后阻塞并等待响应。DefaultFuture类,封装了请求和响应:

// 省略其他代码
public class DefaultFuture implements ResponseFuture {
    private final Lock                           lock = new ReentrantLock();
    private final Condition                      done = lock.newCondition();
    //waiting map
    private static final Map<Long, DefaultFuture> FUTURES 
                = new ConcurrentHashMap<Long, DefaultFuture>();
    private final Request                         request;
    private volatile Response                     response;
}

 

1. consumer发送请求,阻塞等待响应。

调用代码:

HelloService helloService = (HelloService) appCtx.getBean("hello");
String hello = helloService.sayHello();

 

调用代理对象的sayHello方法,代理类proxy0由javassist动态生成,代码大致如下:

class com.alibaba.dubbo.common.bytecode.proxy0 implements
    com.alibaba.dubbo.rpc.service.EchoService, com.zhang.HelloService {
    public <init>(java.lang.reflect.InvocationHandler arg0){
        handler=$1;
    }
    public static java.lang.reflect.Method[] methods;
    private java.lang.reflect.InvocationHandler handler;
    
    public java.lang.String sayHello(){
        Object[] args = new Object[0];
        //handler是InvokerInvocationHandler对象
        Object ret = handler.invoke(this, methods[0], args);
        return (java.lang.String)ret;
    }
    public java.lang.Object $echo(java.lang.Object arg0){
        Object[] args = new Object[1];
        args[0] = ($w)$1;
        Object ret = handler.invoke(this, methods[1], args);
        return (java.lang.Object)ret;
    }
}

 

进InvokerInvocationHandler

//InvokerInvocationHandler类
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    Class<?>[] parameterTypes = method.getParameterTypes();
    if (method.getDeclaringClass() == Object.class) {
        return method.invoke(invoker, args);
    }
    if ("toString".equals(methodName) && parameterTypes.length == 0) {
        return invoker.toString();
    }
    if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
        return invoker.hashCode();
    }
    if ("equals".equals(methodName) && parameterTypes.length == 1) {
        return invoker.equals(args[0]);
    }
    //invoker是MockClusterInvoker
    return invoker.invoke(new RpcInvocation(method, args)).recreate();
}

 

跳过中间步骤,进到DubboInvoker的doInvoke方法,只分析一般的阻塞调用

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 {
        boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
        boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
        int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);
        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 {
//currentClient对象是 ReferenceCountExchangeClient/HeaderExchangeClient/HeaderExchangeChannel //拆分来看:ResponseFuture responseFuture = currentClient.request(inv, timeout); // responseFuture.get(); 调用get导致调用线程阻塞 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); } }

 

进HeaderExchangeChannel

public ResponseFuture request(Object request, int timeout) throws RemotingException {
    if (closed) {
        throw new RemotingException(this.getLocalAddress(), null, 
      "Failed to send request " + request + ", cause: The channel " + this + " is closed!"); } // create request. Request req = new Request(); req.setVersion("2.0.0"); req.setTwoWay(true); req.setData(request); DefaultFuture future = new DefaultFuture(channel, req, timeout); try{ channel.send(req); }catch (RemotingException e) { future.cancel(); throw e; } return future; }

 

进DefaultFuture

public Object get() throws RemotingException {
    return get(timeout);
}

public Object get(int timeout) throws RemotingException {
    if (timeout <= 0) {
        timeout = Constants.DEFAULT_TIMEOUT;
    }
    if (! isDone()) {
        long start = System.currentTimeMillis();
        lock.lock();
        try {
            while (!isDone()) {
                //调用线程等待直到超时,或者被DubboClientHandler线程唤醒
                done.await(timeout, TimeUnit.MILLISECONDS);
                if (isDone() || System.currentTimeMillis() - start > timeout) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        if (! isDone()) {
            throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
        }
    }
    return returnFromResponse();
}

private Object returnFromResponse() throws RemotingException {
    Response res = response;
    if (res == null) {
        throw new IllegalStateException("response cannot be null");
    }
    if (res.getStatus() == Response.OK) {
        return res.getResult();
    }
    if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
        throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, 
    channel, res.getErrorMessage()); }
throw new RemotingException(channel, res.getErrorMessage()); }

 

2. 在DubboClientHandler线程中,consumer接收响应,唤醒调用线程。

 

从ChannelEventRunnable进

//ChannelEventRunnable类
public void run() {
    //省略其他代码
    switch (state) {
        case RECEIVED:
            handler.received(channel, message);break;
        default:
            logger.warn("unknown state: " + state + ", message is " + message);
    }
}

 

进DecodeHandler

public void received(Channel channel, Object message) throws RemotingException {
    if (message instanceof Decodeable) {
        decode(message);
    }

    if (message instanceof Request) {
        decode(((Request)message).getData());
    }

    if (message instanceof Response) {
        decode( ((Response)message).getResult());
    }

    handler.received(channel, message);
}

 

进HeaderExchangeHandler

public void received(Channel channel, Object message) throws RemotingException {
    channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
    ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
    try {
        if (message instanceof Request) {
            // handle request.
            Request request = (Request) message;
            if (request.isEvent()) {
                handlerEvent(channel, request);
            } else {
                if (request.isTwoWay()) {
                    Response response = handleRequest(exchangeChannel, request);
                    channel.send(response);
                } else {
                    handler.received(exchangeChannel, request.getData());
                }
            }
        } else if (message instanceof Response) {
            handleResponse(channel, (Response) message);
        } else if (message instanceof String) {
            if (isClientSide(channel)) {
                Exception e = new Exception("Dubbo client can not supported string message: "
               + message + " in channel: " + channel + ", url: " + channel.getUrl()); logger.error(e.getMessage(), e); } else { String echo = handler.telnet(channel, (String) message); if (echo != null && echo.length() > 0) { channel.send(echo); } } } else { handler.received(exchangeChannel, message); } } finally { HeaderExchangeChannel.removeChannelIfDisconnected(channel); } } static void handleResponse(Channel channel, Response response) throws RemotingException { if (response != null && !response.isHeartbeat()) { DefaultFuture.received(channel, response); } }

 

进DefaultFuture

public static void received(Channel channel, Response response) {
    try {
        //收到响应删除future
        DefaultFuture future = FUTURES.remove(response.getId());
        if (future != null) {
            future.doReceived(response);
        } else {
            logger.warn("The timeout response finally returned at " 
                        + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) 
                        + ", response " + response 
                        + (channel == null ? "" : ", channel: " + channel.getLocalAddress() 
                            + " -> " + channel.getRemoteAddress()));
        }
    } finally {
        CHANNELS.remove(response.getId());
    }
}

private void doReceived(Response res) {
    lock.lock();
    try {
        //给响应赋值
        response = res;
        if (done != null) {
            //DubboClientHandler线程唤醒调用线程
            done.signal();
        }
    } finally {
        lock.unlock();
    }
    if (callback != null) {
        invokeCallback(callback);
    }
}

可以看到实际是两个线程在通信,main线程发送调用请求,并阻塞,DubboClientHandler线程接收到响应,并唤醒主线程。

DubboClientHandler是一个线程池,它执行工作队列中的任务(即ChannelEventRunnable对象)。

又是谁把ChannelEventRunnable对象放到DubboClientHandler线程池的工作队列中的呢?答案是New I/O client worker

//AllChannelHandler类
public void received(Channel channel, Object message) throws RemotingException {
    //DubboClientHandler线程池
    ExecutorService cexecutor = getExecutorService();
    try {
        cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
    } catch (Throwable t) {
        throw new ExecutionException(message, channel, getClass() + 
                  " error when process received event .", t);
    }
}

 

如果一个方法没有返回值,声明为:public void sayHello();
但配置不是oneway,那么cosumer还是会返回RpcResult,但是RpcResult中的内容为空。

posted on 2018-01-03 16:37  偶尔发呆  阅读(1052)  评论(0编辑  收藏  举报