赵计刚
每天进步一点点

服务端请求解码总体流程

 1 NettyCodecAdapter$InternalDecoder.decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out)
 2 -->new NettyBackedChannelBuffer(ByteBuf buffer) // 创建一个buffer
 3 -->NettyChannel.getOrAddChannel(io.netty.channel.Channel ch, URL url, ChannelHandler handler)
 4 -->DubboCountCodec.decode(Channel channel, ChannelBuffer buffer)
 5   -->ExchangeCodec.decode(Channel channel, ChannelBuffer buffer)
 6     -->buffer.readBytes(header); //读取header byte[]
 7     -->decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)
 8       -->检查魔数、检查总长度是否大于等于16
 9       -->获取请求体长度
10       -->new ChannelBufferInputStream(buffer, len)
11       -->DubboCodec.decodeBody(Channel channel, InputStream is, byte[] header)
12         -->CodecSupport.getSerialization(URL url, Byte id) //解析出请求头header[2]中的序列化ID,根据该ID获取与请求编码相同的序列化协议
13         -->Bytes.bytes2long(header, 4) //获取requestID
14         <!-- 之后创建一个新的Request对象,将requestID及后续解析出来的各种request属性塞入该对象中 -->
15         -->new DecodeableRpcInvocation(channel, req, is, proto)
16           -->DecodeableRpcInvocation.decode()
17             -->decode(Channel channel, InputStream input) //解析请求体参数并将其构造为一个DecodeableRpcInvocation,最终塞到Request对象的data属性中
18               -->new Hessian2ObjectInput(InputStream is)
19               -->反序列化:in.readObject()

总体流程

  • 包装请求传过来的ByteBuf为NettyBackedChannelBuffer(简称buffer)
  • 从buffer中读取header
  • 之后检查魔数、检查header+请求体body总长度是否大于等于16
  • 获取请求体body长度
  • 解析出请求头header[2]中的序列化ID,根据该ID获取与请求编码相同的序列化协议
  • 获取requestID
  • 创建Request对象,将requestID及后续解析出来的各种request属性塞入该对象中
  • 反序列化请求体body,并将其设在DecodeableRpcInvocation中,最后该对象设在Request对象的data属性中

解码还是在NettyCodecAdapter中:

 1     private class InternalDecoder extends ByteToMessageDecoder {
 2         protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {
 3             //获取ChannelBuffer
 4             ChannelBuffer message = new NettyBackedChannelBuffer(input);
 5             //获取NettyChannel
 6             NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
 7             Object msg;
 8             int saveReaderIndex;
 9 
10             try {
11                 do {
12                     saveReaderIndex = message.readerIndex();
13                     try {
14                         //解码message
15                         msg = codec.decode(channel, message);
16                     } catch (IOException e) {
17                         throw e;
18                     }
19                     // 如果接收到的消息发生了拆包,则仅仅设置message的readerIndex为当前的saveReaderIndex
20                     if (msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
21                         message.readerIndex(saveReaderIndex);
22                         break;
23                     } else {
24                         //is it possible to go here ?(没有读到任何数据)
25                         if (saveReaderIndex == message.readerIndex()) {
26                             throw new IOException("Decode without read data.");
27                         }
28                         // 如果读到了正常的消息,写入List<Object> out
29                         if (msg != null) {
30                             out.add(msg);
31                         }
32                     }
33                 } while (message.readable());
34             } finally {
35                 NettyChannel.removeChannelIfDisconnected(ctx.channel());
36             }
37         }
38     }

 

一、创建ChannelBuffer

1 ChannelBuffer message = new NettyBackedChannelBuffer(input);

与客户端请求编码类似,最终的得到的message:

1 NettyBackedChannelBuffer
2 -->ByteBuf buffer = SimpleLeakAwareByteBuf
3    -->ByteBuf buf = PooledUnsafeDirectByteBuf

 

二、获取NettyChannel

之后从获取io.netty.channel实例,然后包装在NettyChannel中。

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

与服务端请求解码类似,最终的得到的channel:

1 -->Channel channel = NioSocketChannel
2 -->ChannelHandler handler = NettyServer
3 -->URL url =dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=10.10.10.10&bind.port=20880&channel.readonly.sent=true&codec=dubbo&default.server=netty4&dubbo=2.0.0&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=7294&side=provider&timestamp=1515031737563

 

三、进行解码

这里的codec是:

1 Codec2 codec = 
2 DubboCountCodec
3 -->DubboCodec codec = new DubboCodec()

DubboCountCodec:

 1     public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
 2         int save = buffer.readerIndex();
 3         MultiMessage result = MultiMessage.create();
 4         do {
 5             Object obj = codec.decode(channel, buffer);
 6             if (Codec2.DecodeResult.NEED_MORE_INPUT == obj) {// 如果发生了拆包,则跳出,在下一次依旧从save处读取
 7                 buffer.readerIndex(save);
 8                 break;
 9             } else {
10                 result.addMessage(obj);// 如果消息正常,添加消息到MultiMessage的List messages中
11                 logMessageLength(obj, buffer.readerIndex() - save);
12                 save = buffer.readerIndex();
13             }
14         } while (true);
15         if (result.isEmpty()) {
16             return Codec2.DecodeResult.NEED_MORE_INPUT;
17         }
18         if (result.size() == 1) {
19             return result.get(0);
20         }
21         return result;
22     }

MultiMessage:

1     private final List messages = new ArrayList();
2 
3     public void addMessage(Object msg) {
4         messages.add(msg);
5     }

DubboCodec的父类ExchangeCodec:

1     public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
2         int readable = buffer.readableBytes();// 获取buffer所有的可读字节(header + body)
3         byte[] header = new byte[Math.min(readable, HEADER_LENGTH)];
4         buffer.readBytes(header);// 将buffer中的前16个字节读入header
5         return decode(channel, buffer, readable, header);// 反序列化请求体body,构造成DecodeableRpcResult,塞入Request的data属性中
6     }
 1     protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header) throws IOException {
 2         // check magic number.
 3         if (readable > 0 && header[0] != MAGIC_HIGH
 4                 || readable > 1 && header[1] != MAGIC_LOW) {//魔数不匹配
 5             int length = header.length;
 6             if (header.length < readable) {
 7                 header = Bytes.copyOf(header, readable);
 8                 buffer.readBytes(header, length, readable - length);
 9             }
10             for (int i = 1; i < header.length - 1; i++) {
11                 if (header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
12                     buffer.readerIndex(buffer.readerIndex() - header.length + i);
13                     header = Bytes.copyOf(header, i);
14                     break;
15                 }
16             }
17             return super.decode(channel, buffer, readable, header);
18         }
19         // check length.
20         if (readable < HEADER_LENGTH) {//header+body的总可读数据<16
21             return DecodeResult.NEED_MORE_INPUT;
22         }
23 
24         // 从header中获取body长度
25         int len = Bytes.bytes2int(header, 12);
26         checkPayload(channel, len);//检测body是否超8M了
27 
28         int tt = len + HEADER_LENGTH;
29         if (readable < tt) {// 如果当前可读的消息<header+body总长度(说明发生了拆包)
30             return DecodeResult.NEED_MORE_INPUT;
31         }
32 
33         // limit input stream.
34         ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);
35 
36         try {
37             return decodeBody(channel, is, header);//解码body
38         } finally {
39             if (is.available() > 0) {
40                 try {
41                     if (logger.isWarnEnabled()) {
42                         logger.warn("Skip input stream " + is.available());
43                     }
44                     StreamUtils.skipUnusedStream(is);
45                 } catch (IOException e) {
46                     logger.warn(e.getMessage(), e);
47                 }
48             }
49         }
50     }

DubboCodec:

 1     protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
 2         byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK);// proto:序列化方式ID
 3         Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto);// 根据序列化方式ID获取序列化方式
 4         // get request id.
 5         long id = Bytes.bytes2long(header, 4);// 获取reqID
 6         if ((flag & FLAG_REQUEST) == 0) {
 7             ......
 8             return res;
 9         } else {
10             // decode request.
11             Request req = new Request(id);
12             req.setVersion("2.0.0");
13             req.setTwoWay((flag & FLAG_TWOWAY) != 0);
14             if ((flag & FLAG_EVENT) != 0) {
15                 req.setEvent(Request.HEARTBEAT_EVENT);
16             }
17             try {
18                 Object data;
19                 if (req.isHeartbeat()) {
20                     data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(), is));
21                 } else if (req.isEvent()) {
22                     data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));
23                 } else {
24                     DecodeableRpcInvocation inv;
25                     if (channel.getUrl().getParameter(
26                             Constants.DECODE_IN_IO_THREAD_KEY,
27                             Constants.DEFAULT_DECODE_IN_IO_THREAD)) {
28                         inv = new DecodeableRpcInvocation(channel, req, is, proto);
29                         inv.decode();// 解码请求体
30                     } else {
31                         inv = new DecodeableRpcInvocation(channel, req,
32                                 new UnsafeByteArrayInputStream(readMessageData(is)), proto);
33                     }
34                     data = inv;
35                 }
36                 req.setData(data);
37             } catch (Throwable t) {
38                 if (log.isWarnEnabled()) {
39                     log.warn("Decode request failed: " + t.getMessage(), t);
40                 }
41                 // bad request
42                 req.setBroken(true);
43                 req.setData(t);
44             }
45             return req;
46         }
47     }

就是构造Request参数,重点构造其中的data属性(实际上是一个DecodeableRpcInvocation实例)

DecodeableRpcInvocation:

 1     public void decode() throws Exception {
 2         if (!hasDecoded && channel != null && inputStream != null) {
 3             try {
 4                 decode(channel, inputStream);
 5             } catch (Throwable e) {
 6                 if (log.isWarnEnabled()) {
 7                     log.warn("Decode rpc invocation failed: " + e.getMessage(), e);
 8                 }
 9                 request.setBroken(true);
10                 request.setData(e);
11             } finally {
12                 hasDecoded = true;
13             }
14         }
15     }
 1     public Object decode(Channel channel, InputStream input) throws IOException {
 2         ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
 3                 .deserialize(channel.getUrl(), input);// 创建Hessian2ObjectInput
 4         //下边的读取顺序与序列化时的必须一模一样(我们反序列化"dubbo"=2.0.0时,offset=0, 反序列化"path"=xxx时,offset=6)
 5         setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF());
 6         setAttachment(Constants.PATH_KEY, in.readUTF());
 7         setAttachment(Constants.VERSION_KEY, in.readUTF());
 8 
 9         setMethodName(in.readUTF());
10         try {
11             Object[] args;
12             Class<?>[] pts;
13             String desc = in.readUTF();
14             if (desc.length() == 0) {
15                 pts = DubboCodec.EMPTY_CLASS_ARRAY;
16                 args = DubboCodec.EMPTY_OBJECT_ARRAY;
17             } else {
18                 pts = ReflectUtils.desc2classArray(desc);
19                 args = new Object[pts.length];
20                 for (int i = 0; i < args.length; i++) {
21                     try {
22                         args[i] = in.readObject(pts[i]);
23                     } catch (Exception e) {
24                         if (log.isWarnEnabled()) {
25                             log.warn("Decode argument failed: " + e.getMessage(), e);
26                         }
27                     }
28                 }
29             }
30             setParameterTypes(pts);
31 
32             Map<String, String> map = (Map<String, String>) in.readObject(Map.class);
33             if (map != null && map.size() > 0) {
34                 Map<String, String> attachment = getAttachments();
35                 if (attachment == null) {
36                     attachment = new HashMap<String, String>();
37                 }
38                 attachment.putAll(map);
39                 setAttachments(attachment);
40             }
41             //decode argument ,may be callback
42             for (int i = 0; i < args.length; i++) {
43                 args[i] = decodeInvocationArgument(channel, this, pts, i, args[i]);
44             }
45 
46             setArguments(args);
47 
48         } catch (ClassNotFoundException e) {
49             throw new IOException(StringUtils.toString("Read invocation data failed.", e));
50         }
51         return this;
52     }

上述的setXXX方法,实际上就是为当前的DecodeableRpcInvocation设置各种属性,in.readUTF()和in.readobject都是反序列化的方法,前者将byte[]反序列化为String,后者将byte[]反序列化为Object。

到此为止,服务端请求解码就结束了。

posted on 2018-01-04 20:40  赵计刚  阅读(1077)  评论(0编辑  收藏  举报