Netty之ChannelPipeline(三)Outbound与Inbound事件的传播

  • Outbound事件是请求事件。
  • Outbound事件的发起者是Channel,处理者是Unsafe。
  • Outbound事件在Pipeline中传输方向是tail -> head。

Outbount事件其中之一bind,以bind为例:
AbstractChannel
bind(SocketAddress localAddress, ChannelPromise promise):

@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return pipeline.bind(localAddress, promise);
}
  1. 该方法实现自ChannelOutboundInvoker接口。
  2. 方法内部调用被被bind(SocketAddress localAddress, ChannelPromise promise) 方法。

看bind(SocketAddress localAddress, ChannelPromise promise) 方法的具体实现:

@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    return tail.bind(localAddress, promise);
}
    @Override
 public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
     if (localAddress == null) {
         throw new NullPointerException("localAddress");
     }
     // 判断 Promise 对象是否合法。
     if (isNotValidPromise(promise, false)) {
         // cancelled
         return promise;
     }
 
     // 获得下一个 Outbound 节点
     final AbstractChannelHandlerContext next = findContextOutbound();
     // 获得下一个 Outbound 节点的执行器
     EventExecutor executor = next.executor();
     // 调用下一个 Outbound 节点的 bind 方法
     if (executor.inEventLoop()) {
         next.invokeBind(localAddress, promise);
     } else {
         safeExecute(executor, new Runnable() {
             @Override
             public void run() {
                 next.invokeBind(localAddress, promise);
             }
         }, promise, null);
     }
     return promise;
 }

上面判断promise对象是否合法,isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise)

private boolean isNotValidPromise(ChannelPromise promise, boolean allowVoidPromise) {
    if (promise == null) {
        throw new NullPointerException("promise");
    }

    // Promise 已经完成
    if (promise.isDone()) {
        // Check if the promise was cancelled and if so signal that the processing of the operation
        // should not be performed.
        //
        // See https://github.com/netty/netty/issues/2349
        if (promise.isCancelled()) {
            return true;
        }
        throw new IllegalArgumentException("promise already done: " + promise);
    }

    // Channel 不符合
    if (promise.channel() != channel()) {
        throw new IllegalArgumentException(String.format(
                "promise.channel does not match: %s (expected: %s)", promise.channel(), channel()));
    }

    // DefaultChannelPromise 合法 
    if (promise.getClass() == DefaultChannelPromise.class) {
        return false;
    }
    // 禁止 VoidChannelPromise 
    if (!allowVoidPromise && promise instanceof VoidChannelPromise) {
        throw new IllegalArgumentException(
                StringUtil.simpleClassName(VoidChannelPromise.class) + " not allowed for this operation");
    }
    // 禁止 CloseFuture
    if (promise instanceof AbstractChannel.CloseFuture) {
        throw new IllegalArgumentException(
                StringUtil.simpleClassName(AbstractChannel.CloseFuture.class) + " not allowed in a pipeline");
    }
    return false;
}

关于调用findContextOutbound()方法,获得下一个Outbound节点:
注意从pipeline的tail->head。

private AbstractChannelHandlerContext findContextOutbound() {
    // 循环,向前获得一个 Outbound 节点
    AbstractChannelHandlerContext ctx = this;
    do {
        ctx = ctx.prev;
    } while (!ctx.outbound);
    return ctx;
}

调用 AbstractChannelHandlerContext#executor() 方法,获得下一个Outbound节点的执行器:
如果未设置子执行器,则Channel的EventLoop作为执行器。

// Will be set to null if no child executor should be used, otherwise it will be set to the
// child executor.

// EventExecutor 对象
 
final EventExecutor executor;

@Override
public EventExecutor executor() {
    if (executor == null) {
        return channel().eventLoop();
    } else {
        return executor;
    }
}
  • 如果在EventLoop的线程中,那么调用下一个节点的invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法,传播 bind 事件给下一个节点。
  • 如果不在EventLoop线程中,调用safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg)方法,提交到EventLoop的线程中执行:
private static void safeExecute(EventExecutor executor, Runnable runnable, ChannelPromise promise, Object msg) {
    try {
        // 提交到 EventLoop 的线程中,进行执行任务
        executor.execute(runnable);
    } catch (Throwable cause) {
        try {
            // 发生异常,回调通知 promise 相关的异常
            promise.setFailure(cause);
        } finally {
            // 释放 msg 相关的资源
            if (msg != null) {
                ReferenceCountUtil.release(msg);
            }
        }
    }
}

invokeBind(SocketAddress localAddress, ChannelPromise promise) 方法:

 private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
     if (invokeHandler()) { 
     // 判断是否符合的 ChannelHandler
     // 如果是不符合的ChannelHandler,则跳过该节点。
         try {
             // 调用该 ChannelHandler 的 bind 方法
             ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
         } catch (Throwable t) {
             notifyOutboundHandlerException(t, promise); // 通知 Outbound 事件的传播,发生异常
         }
     } else {
         // 跳过,传播 Outbound 事件给下一个节点
         bind(localAddress, promise);
     }
 }

上面调用InvokeHandler()方法,判断是否是符合的ChannelHandler:

/**
 * Makes best possible effort to detect if {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called
 * yet. If not return {@code false} and if called or could not detect return {@code true}.
 *
 * If this method returns {@code false} we will not invoke the {@link ChannelHandler} but just forward the event.
 * This is needed as {@link DefaultChannelPipeline} may already put the {@link ChannelHandler} in the linked-list
 * but not called {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}.
 */
private boolean invokeHandler() {
    // Store in local variable to reduce volatile reads.
    int handlerState = this.handlerState;
    return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
}

这里。ordered = true的节点,必须与ChannelHandler已添加完毕。
ordered = false的节点,没有ChannelHandler的要求。
bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) 方法:

@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
    unsafe.bind(localAddress, promise);
}

unsafe进行处理。说明Unsafe是bind的处理者。


  • Inbound事件是通知事件。
  • Inbound事件发起者是Unsafe,处理者是TailContext。
  • Inbound事件在Pipeline中传输方向是head -> tail。

Inbound和Outbound很相似,镜像。俺就不说啦。

发布了46 篇原创文章 · 获赞 6 · 访问量 3847

猜你喜欢

转载自blog.csdn.net/weixin_43257196/article/details/104247234