I/O Request via {@link Channel} or{@link ChannelHandlerContext}| +----------------------------------------------------+-----------------+ | ChannelPipeline | | | \|/ | | +----------------------+ +-----------+------------+ | | | Inbound Handler N | | Outbound Handler 1 | | | +----------+-----------+ +-----------+------------+ | | /|\ | | | | \|/ | | +----------+-----------+ +-----------+------------+ | | | Inbound Handler N-1 | | Outbound Handler 2 | | | +----------+-----------+ +-----------+------------+ | | /|\ . | | . . | | [ {@link ChannelInboundInvoker}] [ {@link ChannelOutboundInvoker}()] | | [ 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) | +----------------------------------------------------------------------+ An upstream event is handled by the upstream handlers in the bottom-up direction as shown on the left side of the diagram. An upstream 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 {@link InputStream#read(byte[])}. If an upstream event goes beyond the top upstream handler, it is discarded silently. A downstream event is handled by the downstream handler in the top-down direction as shown on the right side of the diagram. A downstream handler usually generates or transforms the outbound traffic such as write requests. If a downstream event goes beyond the bottom downstream handler, it is handled by an I/O thread associated with the {@link Channel}. The I/O thread often performs the actual output operation such as {@link OutputStream#write(byte[])}.
For example, let us assume that we created the following pipeline:
{@link 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 {@code Upstream} meansit is an upstream handler. The class whose name starts with {@code Downstream} means it is a downstream handler.In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes upstream. When an event goes downstream, the order is 5, 4, 3, 2, 1. On top of this principle, {@link ChannelPipeline} skipsthe evaluation of certain handlers to shorten the stack depth:
A user is supposed to have one or more {@link ChannelHandler}s 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:
{@link ChannelPipeline} pipeline = ...;pipeline.addLast("decoder", new MyProtocolDecoder()); pipeline.addLast("encoder", new MyProtocolEncoder()); pipeline.addLast("executor", new ExecutionHandler(...)); pipeline.addLast("handler", new MyBusinessLogicHandler()); A {@link ChannelHandler} can be added or removed at any time because a{@link ChannelPipeline} is thread safe. For example, you can insert anencryption handler when sensitive information is about to be exchanged, and remove it after the exchange.
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |