天天看点

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

概述

一个问题
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

编码器实现了

ChannelOutboundHandler

,并将出站数据从 一种格式转换为另一种格式,和我们方才学习的解码器的功能正好相反。Netty 提供了一组类, 用于帮助你编写具有以下功能的编码器:

  • 将消息编码为字节
  • 将消息编码为消息

    我们将首先从抽象基类 MessageToByteEncoder 开始来对这些类进行考察

1 抽象类 MessageToByteEncoder

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

解码器通常需要在

Channel

关闭之后产生最后一个消息(因此也就有了 

decodeLast()

方法)

这显然不适于编码器的场景——在连接被关闭之后仍然产生一个消息是毫无意义的

1.1 ShortToByteEncoder

其接受一

Short

 型实例作为消息,编码为

Short

的原子类型值,并写入

ByteBuf

,随后转发给

ChannelPipeline

中的下一个 

ChannelOutboundHandler

每个传出的 Short 值都将会占用 ByteBuf 中的 2 字节

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

1.2 Encoder

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

Netty 提供了一些专门化的 

MessageToByteEncoder

,可基于此实现自己的编码器

WebSocket08FrameEncoder

类提供了一个很好的实例

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

2 抽象类 MessageToMessageEncoder

你已经看到了如何将入站数据从一种消息格式解码为另一种

为了完善这幅图,将展示 对于出站数据将如何从一种消息编码为另一种。

MessageToMessageEncoder

类的 

encode()

方法提供了这种能力

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

为了演示,使用

IntegerToStringEncoder

扩展了

MessageToMessageEncoder

  • 编码器将每个出站 Integer 的 String 表示添加到了该 List 中
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

关于有趣的 MessageToMessageEncoder 的专业用法,请查看 

io.netty.handler. codec.protobuf.ProtobufEncoder

类,它处理了由 Google 的 Protocol Buffers 规范所定义 的数据格式。

一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

writeAndFlush

  • 从tail节点开始往前传播
  • 逐个调用channelHandler#write
  • 逐个调用channelHandler#flush

java对象编码过程

write:写队列

flush:刷新写队列

writeAndFlush: 写队列并刷新

pipeline中的标准链表结构

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

数据从head节点流入,先拆包,然后解码成业务对象,最后经过业务Handler处理,调用write,将结果对象写出去

而写的过程先通过tail节点,然后通过encoder节点将对象编码成ByteBuf,最后将该ByteBuf对象传递到head节点,调用底层的Unsafe写到JDK底层管道

Java对象编码过程

为什么我们在pipeline中添加了encoder节点,java对象就转换成netty可以处理的ByteBuf,写到管道里?

我们先看下调用write的code

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

业务处理器接受到请求之后,做一些业务处理,返回一个

user

  • 然后,user在pipeline中传递
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

情形一

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

情形二

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的
Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

handler 如果不覆盖 flush 方法,就会一直向前传递直到 head 节点

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

落到 

Encoder

节点,下面是 

Encoder

 的处理流程

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的

按照简单自定义协议,将Java对象 User 写到传入的参数 out中,这个out到底是什么?

需知

User

对象,从

BizHandler

传入到

MessageToByteEncoder

时,首先传到

write

Netty 源码深度解析(九) - 编码(上)概述1 抽象类 MessageToByteEncoder2 抽象类 MessageToMessageEncoder一个java对象最后是如何转变成字节流,写到socket缓冲区中去的