初始化
在网络编程 - Netty(Channel)中,Channel的初始化,也提到了会一并初始化ChannelPipeline,一个Channel对应着一个ChannelPipeline。
代码在AbstractChannel类中的构造方法:
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
// 创建一个NioSocketChannel.NioSocketChannelUnsafe的内部类对象
unsafe = newUnsafe();
// 创建一个Pipeline,并把当前的Channel赋值给Pipeline
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
ChannelPipeline的类结构图如下,可以看出ChannelPipeline接口继承了ChannelInboundInvoker和ChannelOutboundInvoker接口。
ChannelInboundInvoker用于入站操作,会调用ChannelPipeline中下一个ChannelInboundHandler的方法,ChannelOutboundInvoker用于出站操作,会调用ChannelPipeline中下一个ChannelOutboundHandler的方法。
DefaultChannelPipeline的构造函数,除了ChannelFuture、Channel、Promise外,还构造了TailContext和HeadContext,再通过next和prev把两个链接起来。
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;
}
TailContext的类结构图:
可以看出,HeadContext比TailContext多继承了ChannelOutboundHandler接口。
TailContext构造方法,设置pipline,并标志inbound为true。通过类结构图,看出这两个即是ChannelHandler也是ChannelHandlerContext。
TailContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, TAIL_NAME, true, false);
setAddComplete();
}
HeadContext构造方法,设置pipline,并标志outbound为true,另外还设置了unsafe,因为出站涉及到于socket交互。
HeadContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, HEAD_NAME, false, true);
unsafe = pipeline.channel().unsafe();
setAddComplete();
}
addLast
在网络编程 - Netty(Channel)中,提到了Channel的初始化,即channel = channelFactory.newChannel()
,这句执行完后,就执行init(channel)
方法。
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(config.handler());
// 部分代码略
}
addLast方法:
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
// 检查是否安全
checkMultiplicity(handler);
// 根据handler创建一个AbstractChannelHandlerContext
newCtx = newContext(group, filterName(name, handler), handler);
// 把新的AbstractChannelHandlerContext加入到链表倒二
addLast0(newCtx);
if (!registered) {
newCtx.setAddPending();
// 给pendingHandlerCallbackHead赋值,并传递newCtx
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
checkMultiplicity,在网络编程 - 初识Netty的服务端的例子,EchoServerHandler 是有@ChannelHandler.Sharable注解的,用来标识能被多个channel安全的共享,是线程安全的。如果一个没有表示线程安全的,又被重复使用,就需要抛异常。
private static void checkMultiplicity(ChannelHandler handler) {
if (handler instanceof ChannelHandlerAdapter) {
// 如果没有@Sharable注解,且已经加入过了,则抛异常
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
// 设置已加入
h.added = true;
}
}
根据handler创建一个AbstractChannelHandlerContext。
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
// isInbound判断是否是ChannelInboundHandler类型
// isOutbound判断是否是ChannelOutboundHandler类型
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
}
addLast0,把新的AbstractChannelHandlerContext加入到链表倒二,headContext <-> nextContext变成headContext <-> newCtx <-> nextContext。
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
invokeHandlerAddedIfNeeded
在Channel成功调用doRegister方法注册后,会调用DefaultChannelPipeline类中的invokeHandlerAddedIfNeeded()
方法。
方法调用链是DefaultChannelPipeline#invokeHandlerAddedIfNeeded() -> DefaultChannelPipeline#callHandlerAddedForAllHandlers() -> PendingHandlerCallback#execute() -> PendingHandlerCallback#callHandlerAdded0() -> ChannelInitializer#handlerAdded() -> ChannelInitializer#initChannel()。
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
try {
// 这个方法,会执行我们在.handler(new ChannelInitializer()里面的内容
initChannel((C) ctx.channel());
} catch (Throwable cause) {
exceptionCaught(ctx, cause);
} finally {
// 移除ChannelInitializer
remove(ctx);
}
return true;
}
return false;
}
private void remove(ChannelHandlerContext ctx) {
try {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
} finally {
initMap.remove(ctx);
}
}
综上,我们的双向链表由headContext <-> nextContext变成headContext <-> ChannelInitializer <-> nextContext变成headContext <-> ChannelInitializer <-> newCtx2 <-> newCtx1 <-> nextContext变成headContext <-> newCtx2 <-> newCtx1 <-> nextContext。因为这个时候,ChannelInitializer完成了自己的使命,即执行他的initChannel方法。
关系图
Channel、ChannelPipeline、ChannelHandler 以及ChannelHandlerContext 之间的关系。综合这篇和Channel那篇,可以总结出,Channel初始化时,会创建一个ChannelPipeline,ChannelPipeline内部维护这HeadContext和TailContext,ChannelPipeline会add多个ChannelHandler时,会把ChannelHandler保证成HandlerContext,再与已有的双向链表连接起来。