Netty中pipeline的创建在AbstractChannel的的构造函数中,这里会创建一个DefaultChannelPipeline,所以一个channel和一个pipeline绑定
下面来看看DefaultChannelPipeline的构造函数
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
可以看到,这里会创建head、tail两个节点
这里说明一下,pipeline里保存着一个双向链表,每个节点都继承自AbstractChannelHandlerContext(这个类里包含一个ChannelHandler成员变量),而AbstractChannelHandlerContext实现了ChannelHandlerContext这个接口
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
Channel channel();
EventExecutor executor();
String name();
ChannelHandler handler();
boolean isRemoved();
ChannelHandlerContext fireChannelRegistered();
ChannelHandlerContext fireChannelUnregistered();
ChannelHandlerContext fireChannelActive();
ChannelHandlerContext fireChannelInactive();
ChannelHandlerContext fireExceptionCaught(Throwable cause);
ChannelHandlerContext fireUserEventTriggered(Object evt);
ChannelHandlerContext fireChannelRead(Object msg);
ChannelHandlerContext fireChannelReadComplete();
ChannelHandlerContext fireChannelWritabilityChanged();
ChannelHandlerContext read();
ChannelHandlerContext flush();
ChannelPipeline pipeline();
ByteBufAllocator alloc();
<T> Attribute<T> attr(AttributeKey<T> key);
<T> boolean hasAttr(AttributeKey<T> key);
}
可以看到,这个接口的主要功能有
- 保存所属的channel
- 保存包含了channelHandler
- 保存所属的pipeline
- 判断channelHandler是否被移除
- 触发channel上的各种事件,传播异常
- 分配bytebuf
- 保存属性attrs
Tail节点
来看看TailContext这个类
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler
注意到这个类实现了ChannelInboundHandler接口,所以他是用于处理inbound事件的
public ChannelHandler handler() {
return this;
}
注意这里,它既是一个AbstractChannelHandlerContext,也是一个ChannelHandler
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
onUnhandledInboundUserEventTriggered(evt);
}
protected void onUnhandledInboundUserEventTriggered(Object evt) {
// This may not be a configuration error and so don't log anything.
// The event may be superfluous for the current pipeline configuration.
ReferenceCountUtil.release(evt);
}
如果用户自定义的事件没有被之前的handler处理而传播到了这里,那么tail节点会释放该evt所占用的内存
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
onUnhandledInboundException(cause);
}
protected void onUnhandledInboundException(Throwable cause) {
try {
logger.warn(
"An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
"It usually means the last handler in the pipeline did not handle the exception.",
cause);
} finally {
ReferenceCountUtil.release(cause);
}
}
如果用户没有处理异常,当异常传播到tail节点时,这里就会打印一条日志并释放相关内存
public void channelRead(ChannelHandlerContext ctx, Object msg) {
onUnhandledInboundMessage(ctx, msg);
}
protected void onUnhandledInboundMessage(ChannelHandlerContext ctx, Object msg) {
onUnhandledInboundMessage(msg);
if (logger.isDebugEnabled()) {
logger.debug("Discarded message pipeline : {}. Channel : {}.",
ctx.pipeline().names(), ctx.channel());
}
}
protected void onUnhandledInboundMessage(Object msg) {
try {
logger.debug(
"Discarded inbound message {} that reached at the tail of the pipeline. " +
"Please check your pipeline configuration.", msg);
} finally {
ReferenceCountUtil.release(msg);
}
}
如果用户没有处理读入的消息,那么tail节点会打印这条消息
Head节点
来看看HeadContext这个类
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler
可以看到head节点既处理inbound事件也处理outbound事件
public ChannelHandler handler() {
return this;
}
与tai节点类似,head节点同时也是一个ChannelHandler
接下来看看head节点传播channelActive事件的方法
public void channelActive(ChannelHandlerContext ctx) {
ctx.fireChannelActive();
readIfIsAutoRead();
}
在之前的文章讲过,这个readIfIsAutoRead方法会向selector注册accept或read事件(取决于不同的channel)
其他传播channel事件的函数都比较简单,这里省略
值得注意的是,这个类有一个Unsafe成员变量,用于读写数据和绑定连接
@Override
public void bind(ChannelHandlerContext ctx,
SocketAddress localAddress,
ChannelPromise promise) {
unsafe.bind(localAddress, promise);
}
@Override
public void connect(
ChannelHandlerContext ctx,
SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) {
unsafe.connect(remoteAddress, localAddress, promise);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) {
unsafe.disconnect(promise);
}
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) {
unsafe.close(promise);
}
@Override
public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) {
unsafe.deregister(promise);
}
@Override
public void read(ChannelHandlerContext ctx) {
unsafe.beginRead();
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
unsafe.write(msg, promise);
}
@Override
public void flush(ChannelHandlerContext ctx) {
unsafe.flush();
}