ChannelInitializer是一个PPLine的初始化工具,可以往PPLine里面设置Handler。

protected abstract void initChannel(C ch) throws Exception;

我们可以重写此方法来完成初始化动作,往PPLine当中加入Handler。

.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
System.out.println("initChannel:" + ch.localAddress());
ch.pipeline().addLast("log", new LoggingHandler(LogLevel.INFO));
ch.pipeline().addLast("DiscardHandler", new DiscardHandler());
ch.pipeline().addLast("hexEncoder2", new HexEncoder2());
ch.pipeline().addLast("hexEncoder1", new HexEncoder1());
}
});


在channel被注册到EventLoop当中时,当前PPLine当中只有一个Handler,就是ChannelInitializer,它的channelRegistered会被调用。在它的initChannel子类回调中往PPLine中加入用户自定义的Handler。

@Override
@SuppressWarnings("unchecked")
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
//调用子类初始化方法,往PPline里加入Handler,该方法只会调用一次。
//在调用之前PPLine当中只有一个handler。 PPline[---this----]
//在调用之后PPLine当中加入了用户自定义的Handler(ABCD) PPline[---this---A---B---C---D---]
if (initChannel(ctx)) {
//重新调用channelRegistered防止事件丢失。
ctx.pipeline().fireChannelRegistered();

//移除当前Handler 移除后变为PPline[---A---B---C---D---]
removeState(ctx);
} else {
//向下传递事件
ctx.fireChannelRegistered();
}
}

子类回到函数,初始化PPLine,成功返回true,同时移除自己。

//子类回调成功返回true,否则返回false
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
//加入标记,保证方法只执行一次
if (initMap.add(ctx)) { // Guard against re-entrance.
try {
//子类回调函数
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
//移除当前Handler
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}

移除标记位。

private void removeState(final ChannelHandlerContext ctx) {
//判断当前ctx是否从PPLine当中移除
if (ctx.isRemoved()) {
//移除执行清空标记位
initMap.remove(ctx);
} else {
// The context is not removed yet which is most likely the case because a custom EventExecutor is used.
// Let's schedule it on the EventExecutor to give it some more time to be completed in case it is offloaded.
//否则加入EventLoop事件队列,下一轮移除。
ctx.executor().execute(new Runnable() {
@Override
public void run() {
initMap.remove(ctx);
}
});
}
}


/**
* {@inheritDoc} If override this method ensure you call super!
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//判断channel是否已经注册
if (ctx.channel().isRegistered()) {
// This should always be true with our current DefaultChannelPipeline implementation.
// The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
// surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
// will be added in the expected order.
//调用子类
if (initChannel(ctx)) {

// We are done with init the Channel, removing the initializer now.
removeState(ctx);
}
}
}