一个{@link ChannelHandler}的列表,它处理或拦截{@link Channel}的入站事件和出站操作。
每个通道都有自己的管道,在创建新通道时自动创建管道。
下图描述了在{@link ChannelPipeline}中{@link ChannelHandler}s如何处理I/O事件。I/O事件由{@link ChannelInboundHandler}或{@link ChannelOutboundHandler}处理,并通过调用{@link ChannelHandlerContext}中定义的事件传播方法(例如{@link ChannelHandlerContext#fireChannelRead(Object)}和{@link ChannelHandlerContext#write(Object)})转发到最近的处理程序。
* I/O Request
* via {@link Channel} or
* {@link ChannelHandlerContext}
* |
* +---------------------------------------------------+---------------+
* | ChannelPipeline | |
* | \|/ |
* | +---------------------+ +-----------+----------+ |
* | | Inbound Handler N | | Outbound Handler 1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler N-1 | | Outbound Handler 2 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ . |
* | . . |
* | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
* | [ method call] [method call] |
* | . . |
* | . \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 2 | | Outbound Handler M-1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 1 | | Outbound Handler M | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* +---------------+-----------------------------------+---------------+
* | \|/
* +---------------+-----------------------------------+---------------+
* | | | |
* | [ Socket.read() ] [ Socket.write() ] |
* | |
* | Netty Internal I/O Threads (Transport Implementation) |
* +-------------------------------------------------------------------+
入站事件由入站处理程序按照自底向上的方向处理,如图左侧所示。入站处理程序通常处理由图底部的I/O线程生成的入站数据。入站数据通常通过实际输入操作从远程对等点读取,例如{@link SocketChannel#read(ByteBuffer)}。如果入站事件超出了顶级入站处理程序,则会悄无声息地丢弃该事件,或者在需要您注意时记录该事件。
出站事件由出站处理程序按照自顶向下的方向处理,如图右侧所示。出站处理程序通常生成或转换出站通信流,如写请求。如果出站事件超出底部出站处理程序,则由与 {@link Channel}关联的I/O线程处理。I/O线程通常执行实际的输出操作,例如{@link SocketChannel#write(ByteBuffer)}。
例如,假设我们创建了以下管道:
* p.addLast("1", new InboundHandlerA());
* p.addLast("2", new InboundHandlerB());
* p.addLast("3", new OutboundHandlerA());
* p.addLast("4", new OutboundHandlerB());
* p.addLast("5", new InboundOutboundHandlerX());
在上面的示例中,名称以{@code Inbound}开头的类意味着它是入站处理程序。名称以{@code Outbound}开头的类意味着它是一个出站处理程序。
在给定的示例配置中,当事件进入入站时,处理程序的评估顺序是1、2、3、4、5。当事件出站时,顺序是5,4,3,2,1。在此原则之上,{@link ChannelPipeline}跳过了对某些处理程序的评估,以缩短堆栈深度:
正如您在图中可能注意到的,处理程序必须调用{@link ChannelHandlerContext}中的事件传播方法,以便将事件转发给下一个处理程序。这些方法包括:
入站事件传播方法:
出站事件传播方法:
下面的例子展示了事件传播通常是如何完成的:
* public class MyInboundHandler extends {@link ChannelInboundHandlerAdapter} {
* {@code @Override}
* public void channelActive({@link ChannelHandlerContext} ctx) {
* System.out.println("Connected!");
* ctx.fireChannelActive();
* }
* }
*
* public class MyOutboundHandler extends {@link ChannelOutboundHandlerAdapter} {
* {@code @Override}
* public void close({@link ChannelHandlerContext} ctx, {@link ChannelPromise} promise) {
* System.out.println("Closing ..");
* ctx.close(promise);
* }
* }
用户应该在管道中有一个或多个{@link ChannelHandler}来接收I/O事件(例如读取)和请求I/O操作(例如写入和关闭)。例如,一个典型的服务器在每个通道的管道中都有以下处理程序,但是根据协议和业务逻辑的复杂性和特征,您的里程可能会有所不同:
可以表示为,如下例所示:
* static final {@link EventExecutorGroup} group = new {@link DefaultEventExecutorGroup}(16);
* ...
*
* {@link ChannelPipeline} pipeline = ch.pipeline();
*
* pipeline.addLast("decoder", new MyProtocolDecoder());
* pipeline.addLast("encoder", new MyProtocolEncoder());
//告诉管道在与I/O线程不同的线程中运行MyBusinessLogicHandler的事件处理程序方法,这样I/O线程就不会被耗时的任务阻塞。
//如果您的业务逻辑是完全异步的,或者非常快地完成,则不需要指定组。
* pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
可以在任何时候添加或删除{@link ChannelHandler},因为{@link ChannelPipeline}是线程安全的。例如,您可以在即将交换敏感信息时插入加密处理程序,并在交换后删除它。
ChannelPipeline addFirst(String name, ChannelHandler handler);在管道的第一个位置插入一个{@link ChannelHandler}。
ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);在管道的第一个位置插入一个{@link ChannelHandler}。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline addLast(String name, ChannelHandler handler);在管道的最后一个位置追加一个{@link ChannelHandler}。
ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);在管道的最后一个位置追加一个{@link ChannelHandler}。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);在该管道的现有handler之前插入{@link ChannelHandler}。
ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);在该管道的现有handler之前插入{@link ChannelHandler}。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);在该管道的现有处理程序之后插入{@link ChannelHandler}。
ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);在该管道的现有处理程序之后插入{@link ChannelHandler}。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline addFirst(ChannelHandler... handlers);在管道的第一个位置插入{@link ChannelHandler}s。
ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);在管道的第一个位置插入{@link ChannelHandler}s。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline addLast(ChannelHandler... handlers);在管道的最后一个位置插入{@link ChannelHandler}s。
ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);在管道的最后一个位置插入{@link ChannelHandler}s。{@link EventExecutorGroup}将用于执行{@link ChannelHandler}方法
ChannelPipeline remove(ChannelHandler handler);从该管道中删除指定的{@link ChannelHandler}。
ChannelHandler remove(String name);从管道中删除具有指定名称的{@link ChannelHandler}。
ChannelHandler removeFirst();删除管道中的第一个{@link ChannelHandler}。
ChannelHandler removeLast();删除此管道中的最后一个{@link ChannelHandler}。
ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);用管道中的newHandler替换指定的{@link ChannelHandler}。
ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);用管道中的新处理程序替换指定名称的{@link ChannelHandler}。
ChannelHandler newHandler);用管道中的新处理程序替换指定类型的{@link ChannelHandler}。
ChannelHandler first();返回此管道中的第一个{@link ChannelHandler}。
ChannelHandlerContext firstContext();返回管道中第一个{@link ChannelHandler}的上下文。
ChannelHandler last();返回此管道中的最后一个{@link ChannelHandler}。
ChannelHandlerContext lastContext();返回此管道中最后一个{@link ChannelHandler}的上下文。
ChannelHandler get(String name);返回管道中指定名称的{@link ChannelHandler}。
ChannelHandlerContext context(ChannelHandler handler);返回此管道中指定的{@link ChannelHandler}的上下文对象。
ChannelHandlerContext context(String name);返回管道中指定名称的{@link ChannelHandler}的上下文对象。
ChannelHandlerContext context(Class extends ChannelHandler> handlerType);返回管道中指定类型的{@link ChannelHandler}的上下文对象。
Channel channel();返回管道所连接的 {@link Channel}
List
Map