类ChannelInitializer

介绍

类ChannelInitializer是一个特殊的ChannelInboundHandler, 当一个Channel被注册到它的EventLoop时, 提供一个简单的方式用于初始化.

它的实现类通常在Bootstrap.handler(ChannelHandler)/ServerBootstrap.handler(ChannelHandler)和ServerBootstrap.childHandler(ChannelHandler)的上下文中使用, 用于构建channel的ChannelPipeline.

public class MyChannelInitializer extends ChannelInitializer {
    public void initChannel(Channel channel) {
     channel.pipeline().addLast("myHandler", new MyHandler());
    }
}

ServerBootstrap bootstrap = ...;
...
bootstrap.childHandler(new MyChannelInitializer());
...

注意这个类被标记为ChannelHandler.Sharable, 因此它的实现类必须可以安全的被重用.

注: 平时实现自己的ChannelInitializer时需要注意这点.

实现

类定义

ChannelInitializer类定义如下, 继承自ChannelInboundHandlerAdapter:

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {}

初始化逻辑实现

ChannelInitializer覆盖了方法channelRegistered(), 在这里实现了自己的初始化逻辑:

@Override
@SuppressWarnings("unchecked")
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception { // step2
    initChannel((C) ctx.channel()); //step3
    ctx.pipeline().remove(this);  //step5
    ctx.fireChannelRegistered();  // step6
}

步骤细节

我们结合前面的实现例子看:

public class MyChannelInitializer extends ChannelInitializer {
    public void initChannel(Channel channel) {  // step3
     channel.pipeline().addLast("myHandler", new MyHandler()); // step4
    }
}

bootstrap.childHandler(new MyChannelInitializer());  //step1

整个初始化的步骤和顺序如下:

  • step1: "bootstrap.childHandler(new MyChannelInitializer());"

    将MyChannelInitializer作为childHandler加入到bootstrap, 而且只加了这一个Handler.

  • step2: bootstrap启动时回调channelRegistered()

    bootstrap在启动后注册所有的handler, 此时会调用它所有的handler的channelRegistered()方法.

    在前面我们只给bootstrap添加了一个handler(即MyChannelInitializer), 因此此时只有这个handler的channelRegistered()方法被调用.

  • step3: 调用"initChannel((C) ctx.channel())"

    ChannelInitializer的channelRegistered()方法实现中, 第一步就是调用抽象方法(模板方法)initChannel(), 实际的实现是MyChannelInitializer的initChannel()方法.

  • step4: add MyHandler()到pipiline

    这里是MyChannelInitializer真正做事情的地方, 添加它需要的handler到pipline.

    例子中只添加了一个, 实际这里通常是添加多个.

  • step5: 将MyChannelInitializer删除

    "ctx.pipeline().remove(this)" 将当前MyChannelInitializer从pipeline中删除,以后的handler就只剩下MyChannelInitializer在step4中添加的handler了.

  • step6:

    "ctx.fireChannelRegistered()" 这里重新激活ChannelRegistered事件, 以便可以通知到step4中添加的各个handler.

下面是整个步骤的流程图:

@startuml

bootstrap -> bootstrap: add MyChannelInitializer to handler
note left: step1

-> bootstrap: start

bootstrap -> bootstrap : create Channel
bootstrap -> bootstrap : register MyChannelInitializer to pipeline
bootstrap ->  bootstrap: fire channelRegistered
note left: step2
ChannelInitializer -> ChannelInitializer : channelRegistered() triggered

group channelRegistered()
ChannelInitializer -> MyChannelInitializer : initChannel()
note left: step3
group initChannel()
MyChannelInitializer -> MyChannelInitializer : add MyHandler to pipeline
note left: step4
end
MyChannelInitializer -->  ChannelInitializer

ChannelInitializer -> ChannelInitializer : remove MyChannelInitializer from pipeline
note left: step5
ChannelInitializer -> ChannelInitializer : fire channelRegistered
note left: step6
end

MyHandler -> MyHandler: channelRegistered() triggered
@enduml

异常处理

类ChannelInitializer对异常处理的方式就是做两个事情:

  1. 打印日志
  2. 关闭channel
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    //1. 打印日志
    logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), cause);
    try {
        ChannelPipeline pipeline = ctx.pipeline();
        // 在关闭channel之前, 检查channel的pipeline中是否还包含当前ChannelInitializer的handler
        if (pipeline.context(this) != null) {
            // 如果有, 去除它
            pipeline.remove(this);
        }
    } finally {
        // 2. 关闭channel
        ctx.close();
    }
}

当然子类可以继续覆盖这个实现. 不过一般都够用了.

results matching ""

    No results matching ""