Netty Associated -- ChannelPipeline

A list of ChannelHandlers which handles or intercepts inbound events and outbound operations of a Channel. ChannelPipeline implements an advanced form of the Intercepting Filter pattern to give a user full control over how an event is handled and how the ChannelHandlers in a pipeline interact with each other.

ChannelPipeline is a list of ChannelHandlers, which is used to process or intercept the inbound (inbound) events or outbound (outbound) operations of Channel. ChannelPipeline implements the Intercepting Filter mode, which enables users to process events between ChannelHandlers in the pipeline interaction.

Creation of a pipeline

create a pipeline

Each channel has its own pipeline and it is created automatically when a new channel is created.

Each channel has its own pipeline, and a new pipeline is automatically created when the channel is created

How an event flows in a pipeline

How events flow in a pipeline

The following diagram describes how I/O events are processed by ChannelHandlers in a ChannelPipeline typically. An I/O event is handled by either a ChannelInboundHandler or a ChannelOutboundHandler and be forwarded to its closest handler by calling the event propagation methods defined in ChannelHandlerContext, such as ChannelHandlerContext.fireChannelRead(Object) and ChannelHandlerContext.write(Object).

The following table describes how a typical I/O event is handled by ChannelHandlers in a ChannelPipeline. An I/O event is handled by either a ChannelInboundHandler or a ChannelOutboundHandler, and by calling the event propagation method defined in the ChannelHandlerContext, it will is forwarded to its nearest handler, such as ChannelHandlerContext.fireChannelRead(Object) and ChannelHandlerContext.write(Object)


 

附注: 顺序是 request --> Socket.read() --> Inbound Handlers --> Context.wirte() -->  Outbound Handlers --> Socket.write() --> Response

An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the diagram. An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the diagram. The inbound data is often read from a remote peer via the actual input operation such as SocketChannel.read(ByteBuffer). If an inbound event goes beyond the top inbound handler, it is discarded silently, or logged if it needs your attention.

An inbound event is handled bottom-up by inbound handlers, as shown on the left side of the diagram above. An inbound handler usually handles inbound data generated by the I/O thread at the bottom of the graph. Inbound data is usually sent from a remote side via Real input operations read, such as SocketChannel.read(ByteBuffer). If an inbound event flows beyond the top inbound handler, it will be discarded, or logged when it needs your attention


An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the diagram. An outbound handler usually generates or transforms the outbound traffic such as write requests. If an outbound event goes beyond the bottom outbound handler, it is handled by an I/O thread associated with the Channel. The I/O thread often performs the actual output operation such as SocketChannel.write(ByteBuffer).

An outbound event is handled top-down by outbound handlers, as shown on the right side of the diagram above. An outbound handler typically generates or transforms outbound traffic such as write requests. If an outbound event flows beyond the The lowest level outbound handler, which will be handled by a Channel-related I/O thread. This I/O is generally represented as a real output operation, such as SocketChannel.write(ByteBuffer)


For example, let us assume that we created the following pipeline:

For example, suppose we created the following pipeline:

复制代码
ChannelPipeline p = ...;
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());
复制代码


In the example above, the class whose name starts with Inbound means it is an inbound handler. The class whose name starts with Outbound means it is a outbound handler.

在上面的例子中, 名字以Inbound开始的类表示一个inbound处理器. 名字已Outbound开始的类表示一个outbound处理器


In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound. When an event goes outbound, the order is 5, 4, 3, 2, 1. On top of this principle, ChannelPipeline skips the evaluation of certain handlers to shorten the stack depth:

在上面给出的例子中, 在时间进站的时候,handler的计算顺序是 1 2 3 4 5. 当时间出站的时候, 顺序是 5 4 3 2 1. 在此原则之上, ChannelPipeline会跳过某一处理器的计算来缩短栈深:

  • 3 and 4 don't implement ChannelInboundHandler, and therefore the actual evaluation order of an inbound event will be: 1, 2, and 5.
  • 3和4没有实现ChannelInboundHandler, 因此实际的入站事件计算顺序是 1 2 5
  • 1 and 2 don't implement ChannelOutboundHandler, and therefore the actual evaluation order of a outbound event will be: 5, 4, and 3.
  • 1和2没有实现ChannelOutboundHandler, 因此实际的出站事件计算顺序是 5 4 3
  • If 5 implements both ChannelInboundHandler and ChannelOutboundHandler, the evaluation order of an inbound and a outbound event could be 125 and 543 respectively.
  • 假如 5 实现了 ChannelInboundHandler , 又实现了 ChannelOutboundHandler, 那么入站顺序和出站顺序将会是 125 和 543

Forwarding an event to the next handler

将事件转发给下一个处理器

As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in ChannelHandlerContext to forward an event to its next handler. Those methods include:

如你在图表中所见, 一个处理器必须调用ChannelHandlerContext的传播方法来将事件转发给下一个处理器, 这些方法包括:

 

  • Inbound event propagation methods:
  • 入站事件传播方法:
复制代码
ChannelHandlerContext.fireChannelRegistered()
ChannelHandlerContext.fireChannelActive()
ChannelHandlerContext.fireChannelRead(Object)
ChannelHandlerContext.fireChannelReadComplete()
ChannelHandlerContext.fireExceptionCaught(Throwable)
ChannelHandlerContext.fireUserEventTriggered(Object)
ChannelHandlerContext.fireChannelWritabilityChanged()
ChannelHandlerContext.fireChannelInactive()
ChannelHandlerContext.fireChannelUnregistered()
复制代码

 

  • Outbound event propagation methods:
  • 出站事件传播方法:
复制代码
ChannelHandlerContext.bind(SocketAddress, ChannelPromise)
ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise)
ChannelHandlerContext.write(Object, ChannelPromise)
ChannelHandlerContext.flush()
ChannelHandlerContext.read()
ChannelHandlerContext.disconnect(ChannelPromise)
ChannelHandlerContext.close(ChannelPromise)
ChannelHandlerContext.deregister(ChannelPromise)
复制代码

 

and the following example shows how the event propagation is usually done:

下面的例子展示了时间传播是怎么完成的:

复制代码
public class MyInboundHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("Connected!");
        ctx.fireChannelActive();
    }
}

public class MyOutboundHandler extends ChannelOutboundHandlerAdapter {
    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
        System.out.println("Closing ..");
        ctx.close(promise);
    }
}
复制代码

 

Building a pipeline

创建一个管道

A user is supposed to have one or more ChannelHandlers in a pipeline to receive I/O events (e.g. read) and to request I/O operations (e.g. write and close). For example, a typical server will have the following handlers in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the protocol and business logic:

一个用户应该在管道中设置一个或多个ChannelHandlers来接收I/O时间(例如read)和请求 I/O 操作(例如write和close).例如, 一个典型的服务器在每个channel的pipeline有如下handlers, 但你的里程可能会根据复杂程度, 协议特征以及业务逻辑有所改变:

1. Protocol Decoder - translates binary data (e.g. ByteBuf) into a Java object.

协议解码器 - 将二进制数据(例如 ByteBuf) 转化为 Java对象


2. Protocol Encoder - translates a Java object into binary data.

协议编码器 - 将Java对象转化为二进制数据


3. Business Logic Handler - performs the actual business logic (e.g. database access).

业务逻辑处理器 - 执行实际业务逻辑(例如数据库访问)


and it could be represented as shown in the following example:

下面是一个代表例子:

复制代码
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
...

ChannelPipeline pipeline = ch.pipeline();

pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());

// Tell the pipeline to run MyBusinessLogicHandler's event handler methods
// in a different thread than an I/O thread so that the I/O thread is not blocked by
// a time-consuming task.
// If your business logic is fully asynchronous or finished very quickly, you don't
// need to specify a group.
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
复制代码

Thread safety

线程安全

A ChannelHandler can be added or removed at any time because a ChannelPipeline is thread safe. For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it after the exchange.

因为一个ChannelPipeline是线程安全的, 所以ChannelHandler可以在任意时间被添加或者删除. 例如, 你可以在需要交换敏感信息的时候插入一个加密处理器, 并在交换完成后移除它.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327019658&siteId=291194637