Handler & Pipeline
ChannelHandler 用来处理 Channel 上的各种事件,分为入站、出站两种。所有 ChannelHandler 被连成一串,就是 Pipeline
- 入站处理器通常是 ChannelInboundHandlerAdapter 的子类,主要用来读取客户端数据,写回结果
 
- 出站处理器通常是 ChannelOutboundHandlerAdapter 的子类,主要对写回结果进行加工
 
打个比喻,每个 Channel 是一个产品的加工车间,Pipeline 是车间中的流水线,ChannelHandler 就是流水线上的各道工序,而后面要讲的 ByteBuf 是原材料,经过很多工序的加工:先经过一道道入站工序,再经过一道道出站工序最终变成产品
先搞清楚顺序,服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
   | new ServerBootstrap()     .group(new NioEventLoopGroup())     .channel(NioServerSocketChannel.class)     .childHandler(new ChannelInitializer<NioSocketChannel>() {         protected void initChannel(NioSocketChannel ch) {             ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){                 @Override                 public void channelRead(ChannelHandlerContext ctx, Object msg) {                     System.out.println(1);                     ctx.fireChannelRead(msg);                                       }             });             ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){                 @Override                 public void channelRead(ChannelHandlerContext ctx, Object msg) {                     System.out.println(2);                     ctx.fireChannelRead(msg);                  }             });             ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){                 @Override                 public void channelRead(ChannelHandlerContext ctx, Object msg) {                     System.out.println(3);                     ctx.channel().write(msg);                  }             });                                       ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){                 @Override                 public void write(ChannelHandlerContext ctx, Object msg,                                    ChannelPromise promise) {                     System.out.println(4);                     ctx.write(msg, promise);                  }             });             ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){                 @Override                 public void write(ChannelHandlerContext ctx, Object msg,                                    ChannelPromise promise) {                     System.out.println(5);                     ctx.write(msg, promise);                  }             });             ch.pipeline().addLast(new ChannelOutboundHandlerAdapter(){                 @Override                 public void write(ChannelHandlerContext ctx, Object msg,                                    ChannelPromise promise) {                     System.out.println(6);                     ctx.write(msg, promise);                  }             });         }     })     .bind(8080);
   | 
 
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13
   | new Bootstrap()     .group(new NioEventLoopGroup())     .channel(NioSocketChannel.class)     .handler(new ChannelInitializer<Channel>() {         @Override         protected void initChannel(Channel ch) {             ch.pipeline().addLast(new StringEncoder());         }     })     .connect("127.0.0.1", 8080)     .addListener((ChannelFutureListener) future -> {         future.channel().writeAndFlush("hello,world");     });
   | 
 
服务器端打印:
可以看到,ChannelInboundHandlerAdapter 是按照 addLast 的顺序执行的,而 ChannelOutboundHandlerAdapter 是按照 addLast 的逆序执行的。ChannelPipeline 的实现是一个 ChannelHandlerContext(包装了 ChannelHandler) 组成的双向链表

- 入站处理器中,ctx.fireChannelRead(msg) 是 调用下一个入站处理器
- 如果注释掉 1 处代码,则仅会打印 1
 
- 如果注释掉 2 处代码,则仅会打印 1 2
 
 
- 3 处的 ctx.channel().write(msg) 会 从尾部开始触发 后续出站处理器的执行
 
- 类似的,出站处理器中,ctx.write(msg, promise) 的调用也会 触发上一个出站处理器
- 如果注释掉 6 处代码,则仅会打印 1 2 3 6
 
 
- ctx.channel().write(msg)  VS  ctx.write(msg)
- 都是触发出站处理器的执行
 
- ctx.channel().write(msg) 从尾部开始查找出站处理器
 
- ctx.write(msg) 是从当前节点找上一个出站处理器
 
- 3 处的 ctx.channel().write(msg) 如果改为 ctx.write(msg) 仅会打印 1 2 3,因为节点3 之前没有其它出站处理器了
 
- 6 处的 ctx.write(msg, promise) 如果改为 ctx.channel().write(msg) 会打印 1 2 3 6 6 6… 因为 ctx.channel().write() 是从尾部开始查找,结果又是节点6 自己
 
 
图1 - 服务端 pipeline 触发的原始流程,图中数字代表了处理步骤的先后次序

演示EmbeddedChannel,方便debug和模拟
