网络编程 - Netty(ChannelPipeline)

初始化

网络编程 - 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接口。
网络编程 - Netty(ChannelPipeline)_第1张图片
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的类结构图:
网络编程 - Netty(ChannelPipeline)_第2张图片
可以看出,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,再与已有的双向链表连接起来。
网络编程 - Netty(ChannelPipeline)_第3张图片

你可能感兴趣的:(netty,java,源码分析)