ChannelHandler 用来处理 Channel 上的各种事件,分为入站、出站两种。所有 ChannelHandler 被连成一串,就是Pipeline。
- 入站处理器通常是 ChannelInboundHandlerAdapter 的子类,主要用来读取客户端数据,写回结果
- 出站处理器通常是 ChannelOutboundHandlerAdapter 的子类,主要对写回结果进行加工
@Slf4j
public class TestPipelineServer {
public static void main(String[] args) {
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel channel) throws Exception {
// 通过channel 拿到pipeline
ChannelPipeline pipeline = channel.pipeline();
// 添加处理器 header -> h1 -> h2 -> h3 -> tail
pipeline.addLast("h1",new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.debug("1");
ByteBuf buf = (ByteBuf) msg;
String name = buf.toString(Charset.defaultCharset());
super.channelRead(ctx, name);// 将数据传给下一个handler,如果不调用,操作链则会断掉
}
});
pipeline.addLast("h2",new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object name) throws Exception {
log.debug("2");
log.debug(name.toString());
super.channelRead(ctx, name);
}
});
pipeline.addLast("h3",new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.debug("3");
// super.channelRead(ctx, msg); // 入站操作到此为止,可以不用继续调用
// 为了验证出站,必须在channel中写入数据
channel.writeAndFlush(ctx.alloc().buffer().writeBytes("server...".getBytes()));
}
});
pipeline.addLast("h4",new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.debug("4");
super.write(ctx, msg, promise);
}
});
pipeline.addLast("h5",new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.debug("5");
super.write(ctx, msg, promise);
}
});
pipeline.addLast("h6",new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.debug("6");
super.write(ctx, msg, promise);
}
});
}
})
.bind(8080);
}
}
逻辑解析:
- 上述处理器:header -> h1 -> h2 -> h3 -> h4 -> h5 -> h6
- 其中:h1、h2、h3 为入站,h4、h5、h6 为出站
- 在入站时,链式是按照顺序执行的,并且上一站点调用下一站点传递数据
- 在出站时,链式是按照倒序执行的
- channel 在调用下一站点时,是从链的末尾开始调用
- ctx 调用下一站点时,是从当前链的站点开始调用
今天的内容就到这里,继续关注,后续更精彩!