Netty——Handler链调用机制及编解码器
文章目录
一、Netty的入站和出站机制
1.1 概述
ChannelHandler是处理入站和出站数据的应用程序逻辑的容器。实现了ChannelInboundHandler接口或ChannelInboundHandlerAdapter后可以接收入站事件和数据,这些数据会被业务逻辑处理。当要给客户端发送响应时,也可以从ChannelInboundHandler冲刷数据。ChannelOutboundHandler原理一样,用来处理出站数据。
ChannelPipeline是提供了ChannelHandler链的容器。以客户端应用程序为例,如果事件的运动方向是从客户端到服务端的,则这些事件为出站的,即客户端发送给服务端的数据会通过pipeline中的一系列ChannelOutboundHandler,并被这些Handler处理,反之则称为入站的。
对于服务器端和客户端而言,接收数据的过程就是入站,发送数据的过程就是出站。
接收数据是入站,因此数据解码是InboundHandler;发送数据是出站,需要将数据编码,因此为OutboundHandler。
- Handler关系图
1.2 Handler 编解码器
当Netty发送或者接收一个消息时,就会发生一次数据转换。入站消息会被解码,从字节转换为另一种格式(如java对象);如果是出站消息,它会被编码成字节。
Netty的编解码器都实现了ChannelInboundHandler或者ChannelOutboundHandler接口,实现了接口的这些类都重写了channelRead方法。
对于每个从入站Channel读取的消息,channelRead会被调用,它会调用由解码器提供的decode()方法进行解码,并将已经解码的字节转发给ChannelPipeline中的下一个ChannelInboundHandler。
1.2.1 ByteToMessageDecoder
由于不知道远程节点是否会一次性发送一个完整的信息,tcp有可能出现粘包、拆包的问题,这个类会对入站数据进行缓冲,直到它准备好被处理。
- decode()方法会根据接收到的数据被调用多次,直到确定没有新的元素被添加到 list,或者是 ByteBuf 没有更多的可读字节为止。
- 此时,如果 List out不为空,就会将 List 的内容传递给下一个 Handler 进行处理,该处理器的方法同样会被调用多次。
- 需要注意的是,编解码过程中的数据类型必须一致,否则将跳过Handler,直接将字节码内容读出。
public class ToIntegerDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() >= 4) {
out.add(in.readInt());
}
}
}
- 每次入站从ByteBuf中读取4字节,将其解码为一个int,然后将它添加到下一个List中。
- 当没有更多元素可以被添加到该List中时,它的内容将会被发送给下一个ChannelInboundHandler。
- int在被添加到List中时,会被自动装箱为Integer。
- 在调用readInt()方法前必须验证所输入的ByteBuf是否具有足够的数据。
1.2.2 ReplayingDecoder
ReplayingDecoder扩展了ByteToMessageDecoder类,使用这个类,不必调用readableBytes()方法,参数S指定了用户状态管理的类型,其中Void代表不需要状态管理。
1.2.3 HttpObjectDecoder
一个HTTP数据的解码器。
二、Handler链调用机制
要求