Netty源码学习——ChannelPipeline模型分析
参考Netty API
A list of ChannelHandler
s which handles or intercepts inbound events and outbount operations of aChannel
.ChannelPipeline
implements an advanced form of theIntercepting Filter pattern to give a user full control over how an event is handled and how theChannelHandler
s
in a pipeline interact with each other.
Creation of a pipeline
Each channel has its own pipeline and it is created automatically when a new channel is created.How an event flows in a pipeline
The following diagram describes how I/O events are processed by ChannelHandler
s in aChannelPipeline
typically. An I/O event is handled
by either aChannelInboundHandler
or aChannelOutboundHandler
and be forwarded to its closest handler by calling the event propagation methods
defined inChannelHandlerContext
, such asChannelHandlerContext.fireChannelRead(Object)
andChannelHandlerContext.write(Object)
.
I/O Request via Channel or 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) | +-------------------------------------------------------------------+
Figure 1
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 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 asSocketChannel.write(ByteBuffer)
.
For example, let us assume that 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 withOutbound
means it is a outbound handler.
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:
- 3 and 4 don‘t implement
ChannelInboundHandler
, and therefore the actual evaluation order of an inbound event will be: 1, 2, and 5. - 1 and 2 implement
ChannelOutboundHandler
, and therefore the actual evaluation order of a outbound event will be: 5, 4, and 3. - If 5 implements both
ChannelInboundHandler
andChannelOutboundHandler
, the evaluation order of an inbound and a outbound event could be 125 and 543 respectively.
Forwarding an event to the next handler
As you might noticed in the diagram shows, a handler has to invoke the event propagation methods inChannelHandlerContext
to forward an event to its next handler. Those methods include:
- 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)
public class MyInboundHandler extendsChannelInboundHandlerAdapter
{@Override
public void channelActive(ChannelHandlerContext
ctx) { System.out.println("Connected!"); ctx.fireChannelActive(); } } public clas MyOutboundHandler extendsChannelOutboundHandlerAdapter
{@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 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:
- Protocol Decoder - translates binary data (e.g.
ByteBuf
) into a Java object. - Protocol Encoder - translates a Java object into binary data.
- Business Logic Handler - performs the actual business logic (e.g. database access).
static finalEventExecutorGroup
group = newDefaultEventExecutorGroup
(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 aChannelPipeline
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.
—————>>>>>>>>>>>>>>>>>>华丽的分界线<<<<<<<<<<<<<<<<<—————————————
Figure1 变形:
+-------------------------------------------------------------------+ | IN | | | | | | | | [(Socket)read] | | | | | | | | \|/ | | +----------+----------+ | | | Inbound Handler 1 | | | +----------+----------+ | | | | | \|/ | | +----------+----------+ | | | Inbound Handler 2 | | | +----------+----------+ | | . | | . | | \./ | | ChannelHandlerContext.FireIN_EVT | | [ method call] | | . | | . | | \./ | | +----------+----------+ | | | Inbound Handler N-1 | | | +----------+----------+ | | \|/ | | | | | +----------+----------+ | | | Inbound Handler N | | | +----------+----------+ | | | | | \|/ | | | | +---------------------------------+---------------------------------+ | | | | | | | Application | | | | | | | +---------------------------------+---------------------------------+ | | | | \|/ | | +-----------+----------+ | | | Outbound Handler 1 | | | +-----------+----------+ | | | | | \|/ | +-----------+----------+ | | | Outbound Handler 2 | | | +-----------+----------+ | | . | | . | | \./ | | ChannelHandlerContext.OUT_EVT() | | [ method call] | | . | | . | | \./ | | +-----------+----------+ | | | Outbound Handler M-1 | | | +-----------+----------+ | | | | | \|/ | | +-----------+----------+ | | | Outbound Handler M | | | +-----------+----------+ | | | | | \|/ | | [(Socket)write] | | | | | | | | \|/ | | | | | OUT | +---------------+-----------------------------------+---------------+
责任链模式:
在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的:
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
责任链模式涉及到的角色如下所示:
● 抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
● 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
Java website development中的filter也是责任链模式!参考文章:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html;
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。