一起学netty(11)handler 和 pipeline 概念的理解
ChannelHandler用来处理Channel上的各种事件(包括建立连接,数据收发,异常处理等)
ChannelHandler分为出站和入栈两种。所有的ChannelHandler被连接成一串,就是一个Pipeline。
入栈处理器通常是ChannelInboundHandlerAdapter的子类,主要用于读取和处理客户端的数据。(包括数据包解码,业务逻辑处理等)
出栈处理器通常是ChannelOutboundHandlerAdapter的子类,主要用于向客户端回写数据的处理。(包括回写数据的编码等)
打个比喻,每个Channel是一个产品的加工车间,Pipeline是车间中的流水线,ChannelHandler就是流水线上的各道工序,ByteBuf是原材料,经过很多工序的加工︰先经过一道道入站工序,再经过一道道出站工序最终变成产品。
从SocketChannel实例中可以获取到ChannelPipeline的实例。调用ChannelPipeline.addLast方法可以将一个事件处理器添加到处理器链的末尾,当然也有其他的方法可以添加到头部,或某个handler的后面等。注意,netty会默认在Pipeline的头部和尾部加一个默认的handler。自定义添加的handler都会在head和tail内部。
程序案例:
public class NettyServer2 {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//添加一个handler(入栈处理器)
pipeline.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("first handler:" + msg.getClass().getName());
Integer data = new Integer(1);
//将数据传给下一个handler处理,如果不执行fireChannelRead方法,下一个handler将不会执行
ctx.fireChannelRead(data);
}
});
//添加一个handler(入栈处理器)
pipeline.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("second handler:" + msg.getClass().getName()+" -> "+msg);
String data = "this is data";
//将数据传给下一个handler处理,如果不执行fireChannelRead方法,下一个handler将不会执行
ctx.fireChannelRead(data);
}
});
//添加一个handler(!!!出栈处理器)
/**
* 当向客户端回写数据的时候会触发
*/
pipeline.addLast(new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("third handler:"+msg);
ctx.fireChannelActive();
}
});
//添加一个handler(入栈处理器)
pipeline.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("fourth handler:" + msg.getClass().getName()+" -> "+msg);
//向客户端回写数据
ctx.writeAndFlush("你好");
}
});
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8077).sync();
channelFuture.channel().closeFuture().sync();
}
}
以上程序Pipeline执行的过程是:head -> first handler -> second handler -> fourth handler -> third handler -> tail
。
当有数据发送的时候会打印如下结果:
为什么fourth handler会在 third handler 前执行,因为third handler是一个出栈处理器,服务器接收到数据后会先执行完入栈处理器,当服务器向客户端回写数据的时候才会执行出栈处理器,所以当fourth handler执行writeAndFlush方法后向客户端发送消息“你好”,此时才会执行third handler做一些数据的处理等操作。
看到这里相信你对handler和pipeline已经有了一个大概的认识,后面将要介绍的编码和解码的问题,以及自定义协议的问题,都和ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter有着直接的联系。所以对handler和pipeline的理解至关重要。