dubbo远程调用源码分析(三):客户端接收反馈后的处理

dubbo远程调用的源码分析,分成了三篇文章地址分别如下:

dubbo远程调用源码分析(一):客户端发送请求

dubbo远程调用源码分析(二):服务端接收请求

dubbo远程调用源码分析(三):客户端接收反馈后的处理


下面是consumer接收到provider反馈时的处理

consumer接收到provider的反馈后,触发NettyClient的事件处理器,该事件对consumer来说是上行事件,触发的是NettyCodecAdapter.DeCoder和NettyHandler

首先是NettyCodecAdapter.DeCoder,调用的是NettyCodecAdapter中的InternalDecoder类的messageReceived()方法:

    private class InternalDecoder extends SimpleChannelUpstreamHandler {


        private com.alibaba.dubbo.remoting.buffer.ChannelBuffer buffer =

               com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;


        @Override

        public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) throws Exception{

            Object o =event.getMessage();

            if (!(o instanceof ChannelBuffer)) {

               ctx.sendUpstream(event);

                return;

            }

 
           ChannelBuffer input = (ChannelBuffer) o;

            int readable = input.readableBytes();

            if(readable <= 0) {

                return;

            }

 
           com.alibaba.dubbo.remoting.buffer.ChannelBuffer message;

            if(buffer.readable()) {

                if(buffer instanceof DynamicChannelBuffer) {

                   buffer.writeBytes(input.toByteBuffer());

                   message = buffer;

                } else{

                    int size = buffer.readableBytes() + input.readableBytes();

                   message =com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(

                           size > bufferSize ? size : bufferSize);

                   message.writeBytes(buffer, buffer.readableBytes());

                   message.writeBytes(input.toByteBuffer());

                }

            } else {

                message =com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(

                       input.toByteBuffer());

            }

 

           NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(),url, handler);

            Object msg;

            int saveReaderIndex;

 

            try {

                //decode object.

                do {

                   saveReaderIndex = message.readerIndex();

                    try{

                       msg = codec.decode(channel, message);

                    }catch (IOException e) {

                       buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;

                       throw e;

                    }

                    if(msg == Codec2.DecodeResult.NEED_MORE_INPUT) {

                       message.readerIndex(saveReaderIndex);

                       break;

                    }else {

                       if (saveReaderIndex == message.readerIndex()) {

                           buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;

                           throw new IOException("Decode without read data.");

                        }

                       if (msg != null) {

                           Channels.fireMessageReceived(ctx, msg, event.getRemoteAddress());

                       }

                    }

                } while(message.readable());

            } finally {

                if(message.readable()) {

                   message.discardReadBytes();

                   buffer = message;

                } else{

                   buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;

                }

               NettyChannel.removeChannelIfDisconnected(ctx.getChannel());

            }

        }

 

        @Override

        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {

            ctx.sendUpstream(e);

        }

    }

和consumer给provider发送消息时调用的是一个方法,方法最后调用了Codec2.decode()方法,这个方法的实现在DubboCodec了的父类ExchangeCodec中:

    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {

        int readable =buffer.readableBytes();

        byte[] header =new byte[Math.min(readable, HEADER_LENGTH)];

       buffer.readBytes(header);

        return decode(channel, buffer, readable, header);

    }

然后decode()方法:

    protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)throws IOException {

        // check magic number.

        if (readable> 0 && header[0] != MAGIC_HIGH

                ||readable > 1 && header[1] != MAGIC_LOW) {

            int length= header.length;

            if(header.length < readable) {

                header= Bytes.copyOf(header, readable);

               buffer.readBytes(header, length, readable - length);

            }

            for (int i= 1; i < header.length - 1; i++) {

                if(header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {

                   buffer.readerIndex(buffer.readerIndex() - header.length + i);

                   header = Bytes.copyOf(header, i);

                   break;

                }

            }

            return super.decode(channel, buffer, readable, header);

        }

        // check length.

        if (readable< HEADER_LENGTH) {

            return DecodeResult.NEED_MORE_INPUT;

        }

 

        // get data length.

        int len =Bytes.bytes2int(header, 12);

       checkPayload(channel, len);

 

        int tt = len +HEADER_LENGTH;

        if (readable< tt) {

            return DecodeResult.NEED_MORE_INPUT;

        }

 

        // limit inputstream.

        ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);

 

        try {

            return decodeBody(channel, is, header);

        } finally {

            if(is.available() > 0) {

                try {

                    if(logger.isWarnEnabled()) {

                       logger.warn("Skip input stream " + is.available());

                    }

                   StreamUtils.skipUnusedStream(is);

                } catch(IOException e) {

                   logger.warn(e.getMessage(), e);

                }

            }

        }

    }

最后return的decodeBody()方法在DubboCodec类中实现:

    protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {

        byte flag =header[2], proto = (byte) (flag & SERIALIZATION_MASK);

        Serialization s= CodecSupport.getSerialization(channel.getUrl(), proto);

        // get requestid.

        long id =Bytes.bytes2long(header, 4);

        if ((flag &FLAG_REQUEST) == 0) {

            // decode response.

            Response res = new Response(id);

            if ((flag& FLAG_EVENT) != 0) {

               res.setEvent(Response.HEARTBEAT_EVENT);

            }

            // get status.

            byte status= header[3];

           res.setStatus(status);

            if (status== Response.OK) {

                try {

                   Object data;

                    if(res.isHeartbeat()) {

                       data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(),is));

                    } else if (res.isEvent()) {

                       data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));

                    }else {

                       DecodeableRpcResult result;

                       if (channel.getUrl().getParameter(

                               Constants.DECODE_IN_IO_THREAD_KEY,

                               Constants.DEFAULT_DECODE_IN_IO_THREAD)) {

                           result = new DecodeableRpcResult(channel, res, is,

                                   (Invocation) getRequestData(id), proto);

                           result.decode();

                       } else {

                           result = new DecodeableRpcResult(channel, res,

                                    new UnsafeByteArrayInputStream(readMessageData(is)),

                                   (Invocation) getRequestData(id), proto);

                       }

                       data = result;

                    }

                    res.setResult(data);

                } catch(Throwable t) {

                    if(log.isWarnEnabled()) {

                       log.warn("Decode response failed: " + t.getMessage(), t);

                    }

                   res.setStatus(Response.CLIENT_ERROR);

                   res.setErrorMessage(StringUtils.toString(t));

                }

            } else {

               res.setErrorMessage(deserialize(s, channel.getUrl(), is).readUTF());

            }

            return res;

        } else {

            // decode request.

            Request req= new Request(id);

           req.setVersion("2.0.0");

           req.setTwoWay((flag & FLAG_TWOWAY) != 0);

            if ((flag& FLAG_EVENT) != 0) {

               req.setEvent(Request.HEARTBEAT_EVENT);

            }

            try {

                Object data;

                if(req.isHeartbeat()) {

                   data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(),is));

                } else if (req.isEvent()) {

                   data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));

                } else{

                   DecodeableRpcInvocation inv;

                    if(channel.getUrl().getParameter(

                           Constants.DECODE_IN_IO_THREAD_KEY,

                           Constants.DEFAULT_DECODE_IN_IO_THREAD)) {

                       inv = new DecodeableRpcInvocation(channel, req, is, proto);

                       inv.decode();

                    }else {

                       inv = new DecodeableRpcInvocation(channel, req,

                                new UnsafeByteArrayInputStream(readMessageData(is)), proto);

                    }

                   data = inv;

                }

               req.setData(data);

            } catch(Throwable t) {

                if(log.isWarnEnabled()) {

                   log.warn("Decode request failed: " + t.getMessage(), t);

                }

                // bad request

               req.setBroken(true);

               req.setData(t);

            }

            return req;

        }

    }

provider解析consumer发来的消息时调用的是方法中decode request部分,现在consumer接收provider消息,调用的是方法的decode response部分

首先创建了一个Response对象,从header中得到Response状态,如果status不是OK,则在Response设置ErrorMessage,否则,创建一个DecodeableRpcResult对象,然后调用他的decode()方法

DecodeableRpcResult的decode()方法如下:

    public Object decode(Channel channel, InputStream input) throws IOException {

        ObjectInput in= CodecSupport.getSerialization(channel.getUrl(), serializationType)

               .deserialize(channel.getUrl(), input);

 

        byte flag =in.readByte();

        switch (flag) {

            case DubboCodec.RESPONSE_NULL_VALUE:

                break;

            case DubboCodec.RESPONSE_VALUE:

                try {

                   Type[] returnType = RpcUtils.getReturnTypes(invocation);

                   setValue(returnType == null || returnType.length == 0 ? in.readObject():

                           (returnType.length == 1 ? in.readObject((Class<?>) returnType[0])

                                    :in.readObject((Class<?>) returnType[0], returnType[1])));

                } catch(ClassNotFoundException e) {

                   throw new IOException(StringUtils.toString("Read response datafailed.", e));

                }

                break;

            case DubboCodec.RESPONSE_WITH_EXCEPTION:

                try {

                   Object obj = in.readObject();

                    if(obj instanceof Throwable == false)

                       throw new IOException("Response data error, expect Throwable, butget " + obj);

                    setException((Throwable) obj);

                } catch(ClassNotFoundException e) {

                   throw new IOException(StringUtils.toString("Read response datafailed.", e));

                }

                break;

            default:

                throw new IOException("Unknown result flag, expect '0' '1' '2', get " +flag);

        }

        return this;

    }

首先是反序列化,然后判断返回值类型

如果没有返回值类型,也就是flag=DubboCodec.RESPONSE_NULL_VALUE,则直接break退出switch

如果返回值类型里有异常,也就是flag=DubboCodec.RESPONSE_WITH_EXCEPTION,则调用父类的setException()方法,设置Exception属性并退出switch

如果返回值有类型,也就是flag=DubboCodec.RESPONSE_VALUE,则调用父类的setValue()方法设置Value属性然后退出switch

DecodeableRpcResult的父类是RpcResult类。

至此,事件的NettyCodecAdapter.DeCoder部分处理完毕,然后是NettyHandler的处理,调用的是NettyHandler的messageReceived()方法:

    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

        NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler);

        try {

           handler.received(channel, e.getMessage());

        } finally {

           NettyChannel.removeChannelIfDisconnected(ctx.getChannel());

        }

    }

然后是DecodeHandler类的received方法:

    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类的received()方法:

    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 stringmessage: " + 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);

        }

    }

这里的message是一个Response对象,要调用handleResponse()方法:

    static void handleResponse(Channel channel, Response response) throws RemotingException {

        if (response !=null && !response.isHeartbeat()) {

           DefaultFuture.received(channel, response);

        }

    }

这个方法的if判断里要求这个response不能是心跳,目测dubbo接口之间的心跳检测也是用这个方法的,这个方法调用了DefaultFuture类的received()方法:

    public static void received(Channel channel, Response response) {

        try {

           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(newDate()))

                       + ", response " + response

                       + (channel == null ? "" : ", channel: " +channel.getLocalAddress()

                       + " -> " + channel.getRemoteAddress()));

            }

        } finally {

           CHANNELS.remove(response.getId());

        }

    }

FUTURES是个<long,DefaultFuture>类型的map,首先从这个map中把这个Response删除,然后调用DefaultFuture的doReceived()方法:

    private void doReceived(Response res) {

        lock.lock();

        try {

            response =res;

            if (done !=null) {

               done.signal();

            }

        } finally {

           lock.unlock();

        }

        if (callback !=null) {

           invokeCallback(callback);

        }

    }

这个方法中用的lock对象是java的重入锁,是java.util.concurrent.locks.ReentrantLock.ReentrantLock这个类的对象,done对象是lock.newCondition()生成的,是java.util.concurrent.locks.Condition这个类的对象,该方法中调用的done.signal()方法的作用是唤醒consumer的调用线程,这个调用线程是consumer把消息发送给provider之后进入阻塞状态的,让线程进入阻塞状态的方法是DefaultFuture类的get()方法:

    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()) {

                   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();

    }

其中done.await方法会使线程阻塞,但是不会一直阻塞,如果在设置的超时时间之后线程依然在阻塞状态,则自动唤醒线程,后面的isDone()方法其实只判断了response是否是null,如果线程因为超时而被唤醒,这个时候Response还是null,就会抛出调用超时的异常,最后,调用returnFromResponse方法,返回Response中的result,代码如下:

    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());

    }

该返对象返对象,该返异常返异常,至此dubbo远程调用的过程就结束了。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值