2.4 服务提供方返回调用结果

服务提供方调用指定服务后,会将调用结果封装到 Response 对象中,并将该对象返回给服务消费方。服务提供方也是通过 NettyChannel 的 send 方法将 Response 对象返回,这个方法在 2.2.1 节分析过,这里就不在重复分析了。本节我们仅需关注 Response 对象的编码过程即可,这里仍然省略一些中间调用,直接分析具体的编码逻辑。

  1. public class ExchangeCodec extends TelnetCodec {
  2. public void encode(Channel channel, ChannelBuffer buffer, Object msg) throws IOException {
  3. if (msg instanceof Request) {
  4. encodeRequest(channel, buffer, (Request) msg);
  5. } else if (msg instanceof Response) {
  6. // 对响应对象进行编码
  7. encodeResponse(channel, buffer, (Response) msg);
  8. } else {
  9. super.encode(channel, buffer, msg);
  10. }
  11. }
  12. protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException {
  13. int savedWriteIndex = buffer.writerIndex();
  14. try {
  15. Serialization serialization = getSerialization(channel);
  16. // 创建消息头字节数组
  17. byte[] header = new byte[HEADER_LENGTH];
  18. // 设置魔数
  19. Bytes.short2bytes(MAGIC, header);
  20. // 设置序列化器编号
  21. header[2] = serialization.getContentTypeId();
  22. if (res.isHeartbeat()) header[2] |= FLAG_EVENT;
  23. // 获取响应状态
  24. byte status = res.getStatus();
  25. // 设置响应状态
  26. header[3] = status;
  27. // 设置请求编号
  28. Bytes.long2bytes(res.getId(), header, 4);
  29. // 更新 writerIndex,为消息头预留 16 个字节的空间
  30. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
  31. ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
  32. ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
  33. if (status == Response.OK) {
  34. if (res.isHeartbeat()) {
  35. // 对心跳响应结果进行序列化,已废弃
  36. encodeHeartbeatData(channel, out, res.getResult());
  37. } else {
  38. // 对调用结果进行序列化
  39. encodeResponseData(channel, out, res.getResult(), res.getVersion());
  40. }
  41. } else {
  42. // 对错误信息进行序列化
  43. out.writeUTF(res.getErrorMessage())
  44. };
  45. out.flushBuffer();
  46. if (out instanceof Cleanable) {
  47. ((Cleanable) out).cleanup();
  48. }
  49. bos.flush();
  50. bos.close();
  51. // 获取写入的字节数,也就是消息体长度
  52. int len = bos.writtenBytes();
  53. checkPayload(channel, len);
  54. // 将消息体长度写入到消息头中
  55. Bytes.int2bytes(len, header, 12);
  56. // 将 buffer 指针移动到 savedWriteIndex,为写消息头做准备
  57. buffer.writerIndex(savedWriteIndex);
  58. // 从 savedWriteIndex 下标处写入消息头
  59. buffer.writeBytes(header);
  60. // 设置新的 writerIndex,writerIndex = 原写下标 + 消息头长度 + 消息体长度
  61. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
  62. } catch (Throwable t) {
  63. // 异常处理逻辑不是很难理解,但是代码略多,这里忽略了
  64. }
  65. }
  66. }
  67. public class DubboCodec extends ExchangeCodec implements Codec2 {
  68. protected void encodeResponseData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {
  69. Result result = (Result) data;
  70. // 检测当前协议版本是否支持带有 attachment 集合的 Response 对象
  71. boolean attach = Version.isSupportResponseAttachment(version);
  72. Throwable th = result.getException();
  73. // 异常信息为空
  74. if (th == null) {
  75. Object ret = result.getValue();
  76. // 调用结果为空
  77. if (ret == null) {
  78. // 序列化响应类型
  79. out.writeByte(attach ? RESPONSE_NULL_VALUE_WITH_ATTACHMENTS : RESPONSE_NULL_VALUE);
  80. }
  81. // 调用结果非空
  82. else {
  83. // 序列化响应类型
  84. out.writeByte(attach ? RESPONSE_VALUE_WITH_ATTACHMENTS : RESPONSE_VALUE);
  85. // 序列化调用结果
  86. out.writeObject(ret);
  87. }
  88. }
  89. // 异常信息非空
  90. else {
  91. // 序列化响应类型
  92. out.writeByte(attach ? RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS : RESPONSE_WITH_EXCEPTION);
  93. // 序列化异常对象
  94. out.writeObject(th);
  95. }
  96. if (attach) {
  97. // 记录 Dubbo 协议版本
  98. result.getAttachments().put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
  99. // 序列化 attachments 集合
  100. out.writeObject(result.getAttachments());
  101. }
  102. }
  103. }

以上就是 Response 对象编码的过程,和前面分析的 Request 对象编码过程很相似。如果大家能看 Request 对象的编码逻辑,那么这里的 Response 对象的编码逻辑也不难理解,就不多说了。接下来我们再来分析双向通信的最后一环 —— 服务消费方接收调用结果。