九、Apache Dubbo 3 协议解析(三)Dubbo协议解析入口讲解

先找入口类:

服务端

  1. org.apache.dubbo.config.bootstrap.DubboBootstrap#start
  2. org.apache.dubbo.config.bootstrap.DubboBootstrap#exportServices
  3. org.apache.dubbo.config.ServiceConfig#export
  4. org.apache.dubbo.config.ServiceConfig#doExport
  5. org.apache.dubbo.config.ServiceConfig#doExportUrls
  6. org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol
  7. org.apache.dubbo.registry.integration.RegistryProtocol#export
  8. org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport
  9. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#export
  10. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer
  11. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer
  12. org.apache.dubbo.remoting.exchange.Exchangers#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.exchange.ExchangeHandler)
  13. org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger#bind
  14. org.apache.dubbo.remoting.Transporters#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.ChannelHandler…)
  15. org.apache.dubbo.remoting.transport.netty4.NettyTransporter#bind
  16. org.apache.dubbo.remoting.transport.netty4.NettyServer#NettyServer
  17. org.apache.dubbo.remoting.transport.AbstractServer#AbstractServer
  18. org.apache.dubbo.remoting.transport.netty4.NettyServer#doOpen

服务端部分我们找到了NettyServer的doOpen方法

	@Override
    protected void doOpen() throws Throwable{
        bootstrap = new ServerBootstrap();

        bossGroup = NettyEventLoopFactory.eventLoopGroup(1, "NettyServerBoss");
        workerGroup = NettyEventLoopFactory.eventLoopGroup(
                getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
                "NettyServerWorker");

        final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
        channels = nettyServerHandler.getChannels();

        bootstrap.group(bossGroup, workerGroup)
                .channel(NettyEventLoopFactory.serverSocketChannelClass())
                .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
                .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // FIXME: should we use getTimeout()?
                        int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
                        NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                        if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
                            ch.pipeline().addLast("negotiation",
                                    SslHandlerInitializer.sslServerHandler(getUrl(), nettyServerHandler));
                        }
                        ch.pipeline()
                        		//我们看到此处为解码
                                .addLast("decoder", adapter.getDecoder())
                                //我们看到此处为编码
                                .addLast("encoder", adapter.getEncoder())
                                .addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS))
                                .addLast("handler", nettyServerHandler);
                    }
                });
        // bind
        ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
        channelFuture.syncUninterruptibly();
        channel = channelFuture.channel();

    }

客户端

  1. org.apache.dubbo.config.bootstrap.DubboBootstrap#start
  2. org.apache.dubbo.config.bootstrap.DubboBootstrap#referServices
  3. org.apache.dubbo.config.utils.ReferenceConfigCache#get(org.apache.dubbo.config.ReferenceConfigBase)
  4. org.apache.dubbo.config.ReferenceConfig#get
  5. org.apache.dubbo.config.ReferenceConfig#init
  6. org.apache.dubbo.config.ReferenceConfig#createProxy
  7. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#refer
  8. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#protocolBindingRefer
  9. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#getClients
  10. org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#initClient
  11. org.apache.dubbo.remoting.exchange.Exchangers#connect(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.exchange.ExchangeHandler)
  12. org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger#connect
  13. org.apache.dubbo.remoting.Transporters#connect(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.ChannelHandler…)
  14. org.apache.dubbo.remoting.transport.netty4.NettyTransporter#connect
  15. org.apache.dubbo.remoting.transport.netty4.NettyClient#NettyClient
  16. org.apache.dubbo.remoting.transport.AbstractClient#AbstractClient
  17. org.apache.dubbo.remoting.transport.netty4.NettyClient#doOpen

客户端部分我们找到了NettyClient的doOpen方法

    @Override
    protected void doOpen() throws Throwable {
        final NettyClientHandler nettyClientHandler = new NettyClientHandler(getUrl(), this);
        bootstrap = new Bootstrap();
        bootstrap.group(NIO_EVENT_LOOP_GROUP)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                //.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getTimeout())
                .channel(socketChannelClass());

        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.max(3000, getConnectTimeout()));
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                int heartbeatInterval = UrlUtils.getHeartbeat(getUrl());

                if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
                    ch.pipeline().addLast("negotiation", SslHandlerInitializer.sslClientHandler(getUrl(), nettyClientHandler));
                }

                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
                ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
                		//我们看到此处为解码
                        .addLast("decoder", adapter.getDecoder())
                        //我们看到此处为编码
                        .addLast("encoder", adapter.getEncoder())
                        .addLast("client-idle-handler", new IdleStateHandler(heartbeatInterval, 0, 0, MILLISECONDS))
                        .addLast("handler", nettyClientHandler);

                String socksProxyHost = ConfigUtils.getProperty(SOCKS_PROXY_HOST);
                if(socksProxyHost != null) {
                    int socksProxyPort = Integer.parseInt(ConfigUtils.getProperty(SOCKS_PROXY_PORT, DEFAULT_SOCKS_PROXY_PORT));
                    Socks5ProxyHandler socks5ProxyHandler = new Socks5ProxyHandler(new InetSocketAddress(socksProxyHost, socksProxyPort));
                    ch.pipeline().addFirst(socks5ProxyHandler);
                }
            }
        });
    }

由以上代码我们看到了解码与编码的调用,我们就来研究下此处代码

final public class NettyCodecAdapter {

    private final ChannelHandler encoder = new InternalEncoder();

    private final ChannelHandler decoder = new InternalDecoder();
    
    public ChannelHandler getEncoder() {
        return encoder;
    }

    public ChannelHandler getDecoder() {
        return decoder;
    }

	


    private class InternalDecoder extends ByteToMessageDecoder {

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {

            ChannelBuffer message = new NettyBackedChannelBuffer(input);

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

            // decode object.
            do {
                int saveReaderIndex = message.readerIndex();
                Object msg = codec.decode(channel, message);
                if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
                    message.readerIndex(saveReaderIndex);
                    break;
                } else {
                    //is it possible to go here ?
                    if (saveReaderIndex == message.readerIndex()) {
                        throw new IOException("Decode without read data.");
                    }
                    if (msg != null) {
                        out.add(msg);
                    }
                }
            } while (message.readable());
        }
    }
}

我们先看编码部分

	//org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter.InternalEncoder
    private class InternalEncoder extends MessageToByteEncoder {

        @Override
        protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
            org.apache.dubbo.remoting.buffer.ChannelBuffer buffer = new NettyBackedChannelBuffer(out);
            //先获取channel
            Channel ch = ctx.channel();
            NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler);
            //基于channel来获取数据
            //这块默认走的DubboCountCodec,我们继续看下该方法
            codec.encode(channel, buffer, msg);
        }
    }

    //org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec#encode
    @Override
    public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
        //继续调用
        codec.encode(channel, buffer, msg);
    }
    //org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#encode
    @Override
    public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
        if (msg instanceof Request) { //处理请求对象
            encodeRequest(channel, buffer, (Request) msg);
        } else if (msg instanceof Response) { //处理响应
            encodeResponse(channel, buffer, (Response) msg);
        } else {
        	//其他的交给上级处理,用于telnet模式
            super.encode(channel, buffer, msg);
        }
    }

我们先看请求编码

	// header length. 消息头的长度
    protected static final int HEADER_LENGTH = 16;
    // magic header. 标示为0-15位
    protected static final short MAGIC = (short) 0xdabb;
    protected static final byte MAGIC_HIGH = Bytes.short2bytes(MAGIC)[0];
    protected static final byte MAGIC_LOW = Bytes.short2bytes(MAGIC)[1];
    // message flag. 消息头中的内容
    protected static final byte FLAG_REQUEST = (byte) 0x80;
    protected static final byte FLAG_TWOWAY = (byte) 0x40;
    protected static final byte FLAG_EVENT = (byte) 0x20;
    protected static final int SERIALIZATION_MASK = 0x1f;
    private static final Logger logger = LoggerFactory.getLogger(ExchangeCodec.class);

	//org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#encodeRequest
       protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {
        //获取序列化方式
        Serialization serialization = getSerialization(channel);
        // header. 写入header信息
        byte[] header = new byte[HEADER_LENGTH];
        // set magic number. 魔数0-15位
        Bytes.short2bytes(MAGIC, header);
        //标记为请求
        // set request and serialization flag.
        header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());
        //是单向还是双向的(异步),即 是否是有返回值的请求
        if (req.isTwoWay()) {
            header[2] |= FLAG_TWOWAY;
        }
        //是否为事件(心跳)
        if (req.isEvent()) {
            header[2] |= FLAG_EVENT;
        }
        //写入当前的请求ID
        // set request id.
        Bytes.long2bytes(req.getId(), header, 4);
        //保存当前写入的位置,将其写入的位置往后面偏移,保留出写入内容大小的位置,先进行写入body内容
        // encode request data.
        int savedWriteIndex = buffer.writerIndex();
        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
        ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
        ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
        //按照数据内容的不同,来写入不同的内容
        if (req.isEvent()) {
            encodeEventData(channel, out, req.getData());
        } else {
        	//进入此方法
            encodeRequestData(channel, out, req.getData(), req.getVersion());
        }
        out.flushBuffer();
        if (out instanceof Cleanable) {
            ((Cleanable) out).cleanup();
        }
        bos.flush();
        bos.close();
        //记录写入BODY的长度
        int len = bos.writtenBytes();
        checkPayload(channel, len);
        //将其写入到header中的位置中
        Bytes.int2bytes(len, header, 12);

        //发送到buffer中
        // write
        buffer.writerIndex(savedWriteIndex);
        buffer.writeBytes(header); // write header.
        buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
    }
    //org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData(org.apache.dubbo.remoting.Channel, org.apache.dubbo.common.serialize.ObjectOutput, java.lang.Object, java.lang.String)
    protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
        RpcInvocation inv = (RpcInvocation) data;
        //写入版本
        out.writeUTF(version);
        // https://github.com/apache/dubbo/issues/6138
        //接口全名
        String serviceName = inv.getAttachment(INTERFACE_KEY);
        if (serviceName == null) {
            serviceName = inv.getAttachment(PATH_KEY);
        }
        out.writeUTF(serviceName);
        //接口版本号
        out.writeUTF(inv.getAttachment(VERSION_KEY));
        //方法名
        out.writeUTF(inv.getMethodName());
        //参数描述
        out.writeUTF(inv.getParameterTypesDesc());
        //参数
        Object[] args = inv.getArguments();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                out.writeObject(encodeInvocationArgument(channel, inv, i));
            }
        }
        //写入所有的附加信息
        out.writeAttachments(inv.getObjectAttachments());
    }

我们再看响应编码

//org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#encodeResponse
protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException {
        int savedWriteIndex = buffer.writerIndex();
        try {
            Serialization serialization = getSerialization(channel);
            // header.
            byte[] header = new byte[HEADER_LENGTH];
            // set magic number.魔数
            Bytes.short2bytes(MAGIC, header);
            // set request and serialization flag. 设置序列化ID
            header[2] = serialization.getContentTypeId();
            if (res.isHeartbeat()) {
                header[2] |= FLAG_EVENT;
            }
            // set response status. 响应状态 成功/失败
            byte status = res.getStatus();
            header[3] = status;
            // set request id.
            Bytes.long2bytes(res.getId(), header, 4);

            //设置响应的结果信息
            buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
            ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
            ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
            // encode response data or error message.
            if (status == Response.OK) {
                if (res.isHeartbeat()) {
                    encodeEventData(channel, out, res.getResult());
                } else {
                	//进入此方法
                    encodeResponseData(channel, out, res.getResult(), res.getVersion());
                }
            } else {
                out.writeUTF(res.getErrorMessage());
            }
            out.flushBuffer();
            if (out instanceof Cleanable) {
                ((Cleanable) out).cleanup();
            }
            bos.flush();
            bos.close();

            //响应的数据包长度
            int len = bos.writtenBytes();
            checkPayload(channel, len);
            Bytes.int2bytes(len, header, 12);
            // write
            buffer.writerIndex(savedWriteIndex);
            buffer.writeBytes(header); // write header.
            buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
        } catch (Throwable t) {
            // clear buffer
            buffer.writerIndex(savedWriteIndex);
            // send error message to Consumer, otherwise, Consumer will wait till timeout.
            if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {
                Response r = new Response(res.getId(), res.getVersion());
                r.setStatus(Response.BAD_RESPONSE);

                if (t instanceof ExceedPayloadLimitException) {
                    logger.warn(t.getMessage(), t);
                    try {
                        r.setErrorMessage(t.getMessage());
                        channel.send(r);
                        return;
                    } catch (RemotingException e) {
                        logger.warn("Failed to send bad_response info back: " + t.getMessage() + ", cause: " + e.getMessage(), e);
                    }
                } else {
                    // FIXME log error message in Codec and handle in caught() of IoHanndler?
                    logger.warn("Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t);
                    try {
                        r.setErrorMessage("Failed to send response: " + res + ", cause: " + StringUtils.toString(t));
                        channel.send(r);
                        return;
                    } catch (RemotingException e) {
                        logger.warn("Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e);
                    }
                }
            }

            // Rethrow exception
            if (t instanceof IOException) {
                throw (IOException) t;
            } else if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else if (t instanceof Error) {
                throw (Error) t;
            } else {
                throw new RuntimeException(t.getMessage(), t);
            }
        }
    }
	//org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#encodeResponse
    protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
        //
        Result result = (Result) data;
        // currently, the version value in Response records the version of Request
        // 是否支持返回attachment参数
        boolean attach = Version.isSupportResponseAttachment(version);
        Throwable th = result.getException();
        if (th == null) {
            //如果没有异常信息,则直接写入内容
            Object ret = result.getValue();
            if (ret == null) {
                out.writeByte(attach ? RESPONSE_NULL_VALUE_WITH_ATTACHMENTS : RESPONSE_NULL_VALUE);
            } else {
                out.writeByte(attach ? RESPONSE_VALUE_WITH_ATTACHMENTS : RESPONSE_VALUE);
                out.writeObject(ret);
            }
        } else {
            //否则的话则将异常信息序列化
            out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION);
            out.writeThrowable(th);
        }

        //支持写入attachment,则写入
        if (attach) {
            // returns current version of Response to consumer side.
            result.getObjectAttachments().put(DUBBO_VERSION_KEY, Version.getProtocolVersion());
            out.writeAttachments(result.getObjectAttachments());
        }
    }

请求/响应结构头图示:

九、Apache Dubbo 3 协议解析(三)Dubbo协议解析入口讲解_第1张图片

请求/响应头信息文字说明

2byte magic:类似java字节码文件里的魔数,用来判断是不是dubbo协议的数据包。魔数是常量0xdabb
1byte 的消息标志位:16-20序列id,21 event,22 two way,23请求或响应标识
1byte 状态,当消息类型为***响应***时,设置响应状态。24-31位。状态位, 设置请求响应状态,dubbo定义了一些响应的类型。具体类型见com.alibaba.dubbo.remoting.exchange.Response
8byte 消息ID,long类型,32-95位。每一个请求的唯一识别id(由于采用异步通讯的方式,用来把请求request和返回的response对应上)
4byte 消息长度,96-127位。消息体 body 长度, int 类型,即记录Body Content有多少个字节。

我们再看解码部分

    //org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter.InternalDecoder#decode
    private class InternalDecoder extends ByteToMessageDecoder {

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {

            ChannelBuffer message = new NettyBackedChannelBuffer(input);

            //首先取到channel
            NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);

            // decode object.
            do {
                //获取数据的长度
                int saveReaderIndex = message.readerIndex();
                //将获取的内容解码,**我们看下这块方法调用**
                Object msg = codec.decode(channel, message);
                //判断是否需要缓存(一次数据包没有完整的信息的话则需要进行缓存 等待下次数据传入)
                if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
                    message.readerIndex(saveReaderIndex);
                    break;
                } else {
                    //is it possible to go here ?
                    if (saveReaderIndex == message.readerIndex()) {
                        throw new IOException("Decode without read data.");
                    }
                    if (msg != null) {
                        out.add(msg);
                    }
                }
            } while (message.readable());
        }
    }
    //org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec#decode
    @Override
    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
        int save = buffer.readerIndex();
        MultiMessage result = MultiMessage.create();
        do {
            //进入此方法
            Object obj = codec.decode(channel, buffer);
            if (Codec2.DecodeResult.NEED_MORE_INPUT == obj) {
                buffer.readerIndex(save);
                break;
            } else {
                result.addMessage(obj);
                logMessageLength(obj, buffer.readerIndex() - save);
                save = buffer.readerIndex();
            }
        } while (true);
        if (result.isEmpty()) {
            return Codec2.DecodeResult.NEED_MORE_INPUT;
        }
        if (result.size() == 1) {
            return result.get(0);
        }
        return result;
    }
    //org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#decode(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.buffer.ChannelBuffer)
    @Override
    public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
        //读取buffer数据,假如:readable=100 byte
        int readable = buffer.readableBytes();
        //HEADER_LENGTH=16 byte,所以此处获取到的是请求头信息
        byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];
        buffer.readBytes(header);
        //进入此方法
        return decode(channel, buffer, readable, header);
    }
    //org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#decode(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.buffer.ChannelBuffer, int, byte[])
    @Override
    protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException {
        // check magic number. 校验 magic
        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. 如果头信息不足 16字节,则说明信息不完成,等待下次数据传入
        if (readable < HEADER_LENGTH) {
            return DecodeResult.NEED_MORE_INPUT;
        }

        // get data length.从头信息的第12个字节开始读取信息,获取到 信息体的数据长度(eg:84)
        int len = Bytes.bytes2int(header, 12);
        checkPayload(channel, len);

		//获取到 信息头+信息体的数据长度(eg:16+84=100)
        int tt = len + HEADER_LENGTH;
        //如果长度不够则说明数据包不完整
        if (readable < tt) {
            return DecodeResult.NEED_MORE_INPUT;
        }

        // limit input stream. 初始化数据流,进行数据读取
        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);
                }
            }
        }
    }

请求/响应解码

   @Override
    protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
        byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);
        // get request id. 获取头信息中第四部分信息 即: request id.
        long id = Bytes.bytes2long(header, 4);
        if ((flag & FLAG_REQUEST) == 0) {
            // decode response. 如果是响应信息
            Response res = new Response(id);
            if ((flag & FLAG_EVENT) != 0) {
            	//是否是event事件
                res.setEvent(true);
            }
            // get status. 获取响应的状态
            byte status = header[3];
            res.setStatus(status);
            try {
                if (status == Response.OK) {//如果是 OK状态
                    Object data;
                    if (res.isEvent()) {
                    	//如果是事件响应
                        ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                        data = decodeEventData(channel, in);
                    } else {
                        DecodeableRpcResult result;
                        if (channel.getUrl().getParameter(DECODE_IN_IO_THREAD_KEY, 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);
                } else {
                    ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                    res.setErrorMessage(in.readUTF());
                }
            } catch (Throwable t) {
            	//如果不成功,直接设置错误状态,并将error信息返回
                if (log.isWarnEnabled()) {
                    log.warn("Decode response failed: " + t.getMessage(), t);
                }
                res.setStatus(Response.CLIENT_ERROR);
                res.setErrorMessage(StringUtils.toString(t));
            }
            return res;
        } else {
            // decode request. 如果是请求信息
            Request req = new Request(id);
            req.setVersion(Version.getProtocolVersion()); //Version.getProtocolVersion() == Dubbo RPC protocol version == 2.0.2
            req.setTwoWay((flag & FLAG_TWOWAY) != 0);
            if ((flag & FLAG_EVENT) != 0) {
                req.setEvent(true);
            }
            try {
                Object data;
                if (req.isEvent()) {
                    ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto);
                    data = decodeEventData(channel, in);
                } else {
                    DecodeableRpcInvocation inv;
                    if (channel.getUrl().getParameter(DECODE_IN_IO_THREAD_KEY, 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;
        }
    }

你可能感兴趣的:(Dubbo,java,spring)