六、Netty的Handler
1、Handler介绍
-
netty的组件设计:Netty的主要组件有
Channel、EventLoop、ChannelFuture、ChannelHandler、ChannelPipe
等 -
我们先来复习一下
ChannelHandler
和ChannelPipeline
的关系。示例图如下:我们可以将pipeline
理解为一个双向链表,ChannelHandlerContext
看作链表中的一个节点,ChannelHandler
则为每个节点中保存的一个属性对象。
-
ChannelHandler
充当了处理入站和出站数据的应用程序逻辑的容器。例如,实现ChannelInboundHandler
接口(或ChannelInboundHandlerAdapter
),你就可以接收入站事件和数据,这些数据会被业务逻辑处理。当要给客户端发送响应时,也可以从ChannelInboundHandler
冲刷数据。业务逻辑通常写在一个或者多个ChannelInboundHandler
中。ChannelOutboundHandler
原理一样,只不过它是用来处理出站数据的 -
ChannelPipeline
提供了ChannelHandler
链的容器。以客户端应用程序为例,如果事件的运动方向是从客户端到服务端的,那么我们称这些事件为出站的,即客户端发送给服务端的数据会通过pipeline
中的一系列ChannelOutboundHandler
,并被这些Handler
处理,反之则称为入站的 -
简单来说,以服务器端为例:接受数据的过程就是入站,发送数据的过程就是出站。客户端也一样。
-
下面,来看看我们常用的
Handler
的关系图:Inbound
处理入站,Outbound
处理出站
-
一般来说,在我们接收数据时将数据解码后,就进行业务的相关处理,所以上图的入站的常用类更多。在数据出站时,一般我们只需要将数据编码后直接发出。
2、Handler链式调用
我们知道,Pipeline
中的Handler
可以当作一个双向链表。但是,Handler
却又存在着入站和出站之分。那么Netty
是如何将两种类型的Handler
保存在一个链表中,却又能够入站的时候调用InboundHandler
,出栈的时候调用OutBoundHandler
呢?看下图,黄色的表示入站,以及入站的Handler
,绿色的表示出站,以及出站的Handler
。
当我们调用如下代码时,我们就会获得一个上图所示的Handler
链表。下面代码时在ChannelInitializer
类中添加Handler
的部分代码。
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LongToByteEncoder()); //out
pipeline.addLast(new ByteToLongDecoder()); //in
pipeline.addLast(new OutBoundHandler()); //out
pipeline.addLast(new InBoundHandler()); //in
}
当一个请求来了的时候,首先会将请求发给pipeline
中位于链表首部的Handler
。如图所示,首先由LongToByteEncoder
(这个东西不管,就是个出站的)接受到入站请求,但是这个东西是个OutBound
。所以它收到入站请求时就不做处理,直接转发给它的下一个ByteToLongDecoder
(这个东西也不管,它是入站的)。这个东西接受到了入站请求了,一看它自己也是一个Inbound
,所以它就将请求的数据进行处理,然后转发给下一个。之后又是一个Outbound
,然后再进行转发,到了最后的InBoundHandler
,在这里我们可以进行业务的处理等等操作。
然后如果需要返回数据,我们就调用writeAndFlush
方法,这个方法可不简单,当他一调用,就会触发出站的请求ÿ