Netty源碼分析(二)--- Server端啓動流程

一、Netty-Server端啓動流程

  1. 從ServerBootstrap的bind方法開始:
    initAndRegister();方法

    //1. 綁定端口
    public ChannelFuture bind(SocketAddress localAddress) {
        validate();
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        return doBind(localAddress);
    }
    
    //2. 調用doBind方法
    private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
    
        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // Registration future is almost always fulfilled already, but just in case it's not.
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                        // IllegalStateException once we try to access the EventLoop of the Channel.
                        promise.setFailure(cause);
                    } else {
                        // Registration was successful, so set the correct executor to use.
                        // See https://github.com/netty/netty/issues/2586
                        promise.registered();
    
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
    
    //3. 調用doBind   →  initAndRegister方法
    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
        	/**
    			反射獲取NioServerSocketChannel(它class是我們傳入的)
    		**/
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }
    
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
    
        // If we are here and the promise is not failed, it's one of the following cases:
        // 1) If we attempted registration from the event loop, the registration has been completed at this point.
        //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
        // 2) If we attempted registration from the other thread, the registration request has been successfully
        //    added to the event loop's task queue for later execution.
        //    i.e. It's safe to attempt bind() or connect() now:
        //         because bind() or connect() will be executed *after* the scheduled registration task is executed
        //         because register(), bind(), and connect() are all bound to the same thread.
    
        return regFuture;
    }
    
    //4. 調用 doBind → initAndRegister → newChannel方法
    public T newChannel() {
       try {
            return clazz.getConstructor().newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }
    
    //5. 調用 doBind → initAndRegister → init方法
    @Override
    void init(Channel channel) throws Exception {
    	//ServerBootstrap創建時如果設置了NioServerSokectChannel的選項,就把它設置進去
        final Map<ChannelOption<?>, Object> options = options0();
        //LinkedHashMap線程不安全
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }
    	//ServerBootstrap創建時如果設置了NioServerSokectChannel的屬性,就把它設置進去
        final Map<AttributeKey<?>, Object> attrs = attrs0();
        //LinkedHashMap線程不安全
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }
    	//拿到pipeline
        ChannelPipeline p = channel.pipeline();
    
        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        //設置客戶端連接的選項
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
        }
         //設置客戶端連接的屬性
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }
    	
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }
    
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }
    
    //6. 調用 doBind → initAndRegister → init → p.addLast方法
    //6 -(1)
    @Override
    public final ChannelPipeline addLast(ChannelHandler... handlers) {
    	//6 -(2)
        return addLast(null, handlers);
    }
    //6 -(2)
    @Override
    public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
        if (handlers == null) {
            throw new NullPointerException("handlers");
        }
    
        for (ChannelHandler h: handlers) {
            if (h == null) {
                break;
            }
            //6 -(3)
            addLast(executor, null, h);
        }
    
        return this;
    }
    //6 -(3)
    @Override
    public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
        	//檢查是否有@Sharable註解(作用:ChannelHandler是否可以在多個channel直接共享)或者 有沒有被使用過,沒有註解且被使用則拋異常
            checkMultiplicity(handler);
    		//ChannelHandler封裝成ChannelHandlerContext (ChannelHandlerContext 是連接ChannelPipeline和ChannelHandler的橋樑)
            newCtx = newContext(group, filterName(name, handler), handler);
    		//6 -(4)
            addLast0(newCtx);
    
            // If the registered is false it means that the channel was not registered on an eventloop yet.
            // In this case we add the context to the pipeline and add a task that will call
            // ChannelHandler.handlerAdded(...) once the channel is registered.
    
    		//進入這裏 並把ChannelHandlerContext包裝成一個任務
            if (!registered) {
                newCtx.setAddPending();
                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;
    }
    //6 -(4)
    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;
    }
    
    
    
    //7. 分析重寫的initChannel方法
    p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                //ServerBootstrap創建時如果設置了NioServerSokectChannel的ChannelHandler ,就把它添加進pipeline中
                ChannelHandler handler = config.handler();
                if (handler != null) {
               		//可以debug看看,這個handler的handlerAdded方法會被回調~~
                    pipeline.addLast(handler);
                }
    			//這裏很重要,用channel綁定的NioEventLoop執行一個任務,把Acceptor派發器添加進NioServerSokectChannel的pipeline中,用於給每個連進來的NioSocketChannel初始化
    			//它傳入NioServerSocketChannel、worker線程組、所有的連接ChannelHandler、選項配置、屬性配置
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                    	//7 -(1)
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
    //7 -(1) ServerBootstrapAcceptor的channelRead方法
    @Override
    @SuppressWarnings("unchecked")
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
    	 //拿到NioSocketChannel
         final Channel child = (Channel) msg;
    	 //將NioSocketChannel的pipeline初始化
         child.pipeline().addLast(childHandler);
    	 //將NioSocketChannel的選項初始化
         setChannelOptions(child, childOptions, logger);
    	 //將NioSocketChannel的屬性初始化
         for (Entry<AttributeKey<?>, Object> e: childAttrs) {
             child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
         }
    
         try {
             //從worker線程組中抽一個NioEventLoop,並將NioSocketChannel註冊到NioEventLoop上和添加監聽器
             childGroup.register(child).addListener(new ChannelFutureListener() {
                 @Override
                 public void operationComplete(ChannelFuture future) throws Exception {
                     if (!future.isSuccess()) {
                         forceClose(child, future.cause());
                     }
                 }
             });
         } catch (Throwable t) {
             forceClose(child, t);
         }
     }
     
    //8. 回到//3. 步
    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
            if (channel != null) {
                // channel can be null if newChannel crashed (eg SocketException("too many open files"))
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
            }
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
        }
    	//boss線程組註冊NioServerSocketChannel  
    	//8 -(1)
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
    
        // If we are here and the promise is not failed, it's one of the following cases:
        // 1) If we attempted registration from the event loop, the registration has been completed at this point.
        //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
        // 2) If we attempted registration from the other thread, the registration request has been successfully
        //    added to the event loop's task queue for later execution.
        //    i.e. It's safe to attempt bind() or connect() now:
        //         because bind() or connect() will be executed *after* the scheduled registration task is executed
        //         because register(), bind(), and connect() are all bound to the same thread.
    
        return regFuture;
    }
     
    //8 -(1)
    @Override
    public ChannelFuture register(Channel channel) {
    	//chooser選擇器獲取一個NioEventLoop並register
    	//8 -(2)
        return next().register(channel);
    }
    
    //8 -(2)
    @Override
    public ChannelFuture register(Channel channel) {
    	//1.創建DefaultChannelPromise,構造器傳入NioServerSocketChannel  和  NioEventLoop
    	//2.register
    	//8 -(3)
        return register(new DefaultChannelPromise(channel, this));
    }
    
    //8 -(3)
    @Override
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        //1.拿到NioMessageUnsafe
        //2.NioMessageUnsafe父類AbstractUnsafe中進行register
        //8 -(4)
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
    
    //8 -(4)  AbstractUnsafe類
    @Override
    public final void register(EventLoop eventLoop, final ChannelPromise promise) {
        if (eventLoop == null) {
            throw new NullPointerException("eventLoop");
        }
        if (isRegistered()) {
            promise.setFailure(new IllegalStateException("registered to an event loop already"));
            return;
        }
        if (!isCompatible(eventLoop)) {
            promise.setFailure(
                    new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
            return;
        }
    	//給NioServerSocketChannel保存NioEnvetLoop
        AbstractChannel.this.eventLoop = eventLoop;
    	//netty的線程模型高性能在於對當前線程身份的確認
    	//eventLoop當前不在自己的線程中
        if (eventLoop.inEventLoop()) {
            register0(promise);
        //這裏eventLoop把boss線程啓動了,把這個runnable加入任務隊列,並啓動boss線程執行
        } else {
            try {
                eventLoop.execute(new Runnable() {
                    @Override
                    public void run() {
                    	//8 -(5)
                        register0(promise);
                    }
                });
            } catch (Throwable t) {
                logger.warn(
                        "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                        AbstractChannel.this, t);
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }
    }
    
    //8 -(5)
    private void register0(ChannelPromise promise) {
       try {
            // check if the channel is still open as it could be closed in the mean time when the register
            // call was outside of the eventLoop
            if (!promise.setUncancellable() || !ensureOpen(promise)) {
                return;
            }
            boolean firstRegistration = neverRegistered;
            //進行註冊
            //8 -(6)
            doRegister();
            neverRegistered = false;
            registered = true;
    
            // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
            // user may already fire events through the pipeline in the ChannelFutureListener.
    		
    		//如果pipeline中有需要執行的HandlerAdded就去執行
    		//8 -(7)
            pipeline.invokeHandlerAddedIfNeeded();
    		
    		//這步告訴ChannelPromise設置成功了
    		//這將影響到第 //2 步中 regFuture.isDone()的判斷結果
            safeSetSuccess(promise);
            
            //8 -(12)
            pipeline.fireChannelRegistered();
            // Only fire a channelActive if the channel has never been registered. This prevents firing
            // multiple channel actives if the channel is deregistered and re-registered.
            if (isActive()) {
                if (firstRegistration) {
                    pipeline.fireChannelActive();
                } else if (config().isAutoRead()) {
                    // This channel was registered before and autoRead() is set. This means we need to begin read
                    // again so that we process inbound data.
                    //
                    // See https://github.com/netty/netty/issues/4805
                    beginRead();
                }
            }
        } catch (Throwable t) {
            // Close the channel directly to avoid FD leak.
            closeForcibly();
            closeFuture.setClosed();
            safeSetFailure(promise, t);
        }
    }
    
    //8 -(6)
    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
            	//1.jdk的註冊,將ServerSocketChannel註冊到Selector上,感興趣事件是0,並把NioServerSocketChannel綁定selectKey//2.有異常就強制刷新一次
            	//3.還是註冊失敗就拋異常
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }
    
    //8 -(7)
    final void invokeHandlerAddedIfNeeded() {
    	//很明顯是在boss線程
        assert channel.eventLoop().inEventLoop();
        if (firstRegistration) {
            firstRegistration = false;
            // We are now registered to the EventLoop. It's time to call the callbacks for the ChannelHandlers,
            // that were added before the registration was done.
            
            //處理之前在//6 -(3)中被包裝成任務的ChannelHandlerContext
            //8 -(8)
            callHandlerAddedForAllHandlers();
        }
    }
    
    //8 -(8)
    private void callHandlerAddedForAllHandlers() {
        final PendingHandlerCallback pendingHandlerCallbackHead;
        synchronized (this) {
            assert !registered;
    
            // This Channel itself was registered.
            registered = true;
    
            pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
            // Null out so it can be GC'ed.
            this.pendingHandlerCallbackHead = null;
        }
    
        // This must happen outside of the synchronized(...) block as otherwise handlerAdded(...) may be called while
        // holding the lock and so produce a deadlock if handlerAdded(...) will try to add another handler from outside
        // the EventLoop.
        PendingHandlerCallback task = pendingHandlerCallbackHead;
        while (task != null) {.
        	//PendingHandlerAddedTask
        	//8 -(8)
            task.execute();
            task = task.next;
        }
    }
    
    //8 -(8)
    @Override
    void execute() {
      EventExecutor executor = ctx.executor();
      //明顯是在當前的NioEventLoop線程中
      if (executor.inEventLoop()) {
      	  //8 -(9)
          callHandlerAdded0(ctx);
      } else {
          try {
              executor.execute(this);
          } catch (RejectedExecutionException e) {
              if (logger.isWarnEnabled()) {
                  logger.warn(
                          "Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
                          executor, ctx.name(), e);
              }
              remove0(ctx);
              ctx.setRemoved();
          }
      }
    }
    
    //8 -(9) 
    private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
        try {
            // We must call setAddComplete before calling handlerAdded. Otherwise if the handlerAdded method generates
            // any pipeline events ctx.handler() will miss them because the state will not allow it.
            ctx.setAddComplete();
            //回調ChannelHandler的handlerAdded方法
            //8 -(10)
            ctx.handler().handlerAdded(ctx);
        } catch (Throwable t) {
            boolean removed = false;
            try {
                remove0(ctx);
                try {
                    ctx.handler().handlerRemoved(ctx);
                } finally {
                    ctx.setRemoved();
                }
                removed = true;
            } catch (Throwable t2) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Failed to remove a handler: " + ctx.name(), t2);
                }
            }
    
            if (removed) {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; removed.", t));
            } else {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; also failed to remove.", t));
            }
        }
    }
    
    //8 -(10)  當前是被回調的是 ChannelInitializer類
    /**
     * {@inheritDoc} If override this method ensure you call super!
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        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.
            
            //8 -(11)
            initChannel(ctx);
        }
    }
    
    //8 -(11) 看完跳回 //8 -(5) 步  還是ChannelInitializer的方法   
    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) { // Guard against re-entrance.
            try {
            	//這個就回到我們 //5 步中重寫的initChannel方法
                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 {
                remove(ctx);
            }
            return true;
        }
        return false;
    }
    
    
    //8 -(12)
    @Override
    public final ChannelPipeline fireChannelRegistered() {
    	//從pipeline的頭結點的下一個結點開始
    	//8 -(13)
        AbstractChannelHandlerContext.invokeChannelRegistered(head);
        return this;
    }
    
    
    
    //8 -(13)
    static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
        	//8 -(14)
            next.invokeChannelRegistered();
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRegistered();
                }
            });
        }
    }
    
    //8 -(14)
    private void invokeChannelRegistered() {
        if (invokeHandler()) {
            try {
    			//調用pipeline上所有的ChannelHandler的channelRegistered方法
    			//8 -(15) 當前調用的是HeadContext
                ((ChannelInboundHandler) handler()).channelRegistered(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRegistered();
        }
    }
    
    //8 -(15)
     @Override
     public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
     	  //head結點中再次檢查pipeline是否有延遲執行的任務
          invokeHandlerAddedIfNeeded();
          //執行ChannelHandlerContext的 fireChannelRegistered方法
          //8 -(16)
          ctx.fireChannelRegistered();
      }
      
    //8 -(16) 頭結點是outBound,此時下一個結點是ChannelInitializer爲inBound,再下一個結點是DefaultChannelPipeline$TailContext爲inBound。必須是inBound的入棧ChannelHandler纔可以執行成功fireChannelRegistered方法
    private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;
    }
    
    //除了第一個ChannelInitializer是初始化就加進pipeline,後面的匿名ChannelHnadler和ServerBootstrapAcceptor都是異步的
    
  2. doBind0方法

    //1. 
    private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
    	//ChannelFuture保存Channel異步操作的結果
    	//官方定義的四種狀態:每種狀態都有對應的方法獲取,netty推薦配合ChannelFutureListener監聽IO事件的完成
    	//並且ChannelHandler中不要await(),因爲它被NioEventLoop線程執行,會死鎖
    	/**
    	 *                                      +---------------------------+
    	 *                                      | Completed successfully    |
    	 *                                      +---------------------------+
    	 *                                 +---->      isDone() = true      |
    	 * +--------------------------+    |    |   isSuccess() = true      |
    	 * |        Uncompleted       |    |    +===========================+
    	 * +--------------------------+    |    | Completed with failure    |
    	 * |      isDone() = false    |    |    +---------------------------+
    	 * |   isSuccess() = false    |----+---->      isDone() = true      |
    	 * | isCancelled() = false    |    |    |       cause() = non-null  |
    	 * |       cause() = null     |    |    +===========================+
    	 * +--------------------------+    |    | Completed by cancellation |
    	 *                                 |    +---------------------------+
    	 *                                 +---->      isDone() = true      |
    	 *                                      | isCancelled() = true      |
    	 *                                      +---------------------------+
    	**/
    	//DefaultChannelPromise是否完成狀態
        if (regFuCture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            //
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        //不是完成狀態
        } else {
            // Registration future is almost always fulfilled already, but just in case it's not.
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            //添加一個監聽器,會在 1. //8 -(5)中safeSetSuccess(promise);方法執行時調用ChannelFutureListener的operationComplete方法
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                        // IllegalStateException once we try to access the EventLoop of the Channel.
                        promise.setFailure(cause);
                    } else {
                        // Registration was successful, so set the correct executor to use.
                        // See https://github.com/netty/netty/issues/2586
                        promise.registered();
    			
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
    
    //2. 
    private static void doBind0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress localAddress, final ChannelPromise promise) {
    
        // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
        // the pipeline in its channelRegistered() implementation.
    	//向NioEventLoop添加一個任務
        channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
            	//如果成功狀態
                if (regFuture.isSuccess()) {
                	//2 -(1)
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }
    
    //2 -(1)
    @Override
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
    	//從尾部TailHandlerContext開始找outBound
    	//2 -(2)
        return tail.bind(localAddress, promise);
    }
    
    //2 -(2)
    @Override
    public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        if (isNotValidPromise(promise, false)) {
            // cancelled
            return promise;
        }
    	//while循環找outbound
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        //在NioEventLoop線程中
        if (executor.inEventLoop()) {
        	//2 -(3)
            next.invokeBind(localAddress, promise);
        } else {
            safeExecute(executor, new Runnable() {
                @Override
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null);
        }
        return promise;
    }
    
    //2 -(3)
    private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
    	//是不是添加的handler
        if (invokeHandler()) {
            try {
            	//此時HeadHandlerContext是outbound
            	//2 -(4)
                ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
            } catch (Throwable t) {
                notifyOutboundHandlerException(t, promise);
            }
        } else {
            bind(localAddress, promise);
        }
    }
    
    //2 -(4)  HeadHandlerContext
    @Override
    public void bind(
            ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
            throws Exception {
        //NioMessageUnsafe
        //2 -(5)
        unsafe.bind(localAddress, promise);
    }
    
    //2 -(5)
    @Override
    public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
        assertEventLoop();
    
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
    
        // See: https://github.com/netty/netty/issues/576
        if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
            localAddress instanceof InetSocketAddress &&
            !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
            !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
            // Warn a user about the fact that a non-root user can't receive a
            // broadcast packet on *nix if the socket is bound on non-wildcard address.
            logger.warn(
                    "A non-root user can't receive a broadcast packet if the socket " +
                    "is not bound to a wildcard address; binding to a non-wildcard " +
                    "address (" + localAddress + ") anyway as requested.");
        }
    	//false
        boolean wasActive = isActive();
        try {
        	//2 -(6)
            doBind(localAddress);
        } catch (Throwable t) {
            safeSetFailure(promise, t);
            closeIfClosed();
            return;
        }
    
        if (!wasActive && isActive()) {
        	//添加一個任務
            invokeLater(new Runnable() {
                @Override
                public void run() {
                	//執行通道的channel激活傳播方法,從頭節點開始
                	//2 -(7)
                    pipeline.fireChannelActive();
                }
            });
        }
    
        safeSetSuccess(promise);
    }
    
    //2 -(6) jdk的bind方法
    @Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }
    
    
    //2 -(7) H
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       ctx.fireChannelActive();
    	//還記得ServerSocketChannel初始化時候註冊的感興趣事件是0吧,這個方法就是把0改成accept事件
    	//2 -(8)
       readIfIsAutoRead();
    }
    
    //2 -(8)
    private void readIfIsAutoRead() {
    	if (channel.config().isAutoRead()) {
    		//2 -(9)
            channel.read();
        }
    }
    
    //2 -(9) AbstractChannel
    @Override
    public Channel read() {
        pipeline.read();
        return this;
    }
    
    //2 -(10) DefaultChannelPipeline
    @Override
    public final ChannelPipeline read() {
    	//從尾節點開始執行read方法
        tail.read();
        return this;
    }
    
    //2 -(11) AbstractChannelHandlerContext 
    @Override
    public ChannelHandlerContext read() {
    	//尾節點開始找Outbound
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
        	//head節點是outbound 執行他的read方法
        	//2 -(12)
            next.invokeRead();
        } else {
            Runnable task = next.invokeReadTask;
            if (task == null) {
                next.invokeReadTask = task = new Runnable() {
                    @Override
                    public void run() {
                        next.invokeRead();
                    }
                };
            }
            executor.execute(task);
        }
    
        return this;
    }
    
    //2 -(12)
    private void invokeRead() {
       if (invokeHandler()) {
            try {
            	//2 -(13)
                ((ChannelOutboundHandler) handler()).read(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            read();
        }
    }
    
    //2 -(13) HeadContext
    @Override
    public void read(ChannelHandlerContext ctx) {
    	 //2 -(14)
         unsafe.beginRead();
     }
    
    //2 -(14)
    @Override
    public final void beginRead() {
         assertEventLoop();
    
         if (!isActive()) {
             return;
         }
    
         try {
         	 //2 -(15)
             doBeginRead();
         } catch (final Exception e) {
             invokeLater(new Runnable() {
                 @Override
                 public void run() {
                     pipeline.fireExceptionCaught(e);
                 }
             });
             close(voidPromise());
         }
     }
    
    //2 -(15) AbstractNioChannel
    @Override
    protected void doBeginRead() throws Exception {
        // Channel.read() or ChannelHandlerContext.read() was called
        final SelectionKey selectionKey = this.selectionKey;
        if (!selectionKey.isValid()) {
            return;
        }
    
        readPending = true;
    	//初始化時候設置的是 0
        final int interestOps = selectionKey.interestOps();
        //readInterestOp=16, 變成ACCEPT事件了
        if ((interestOps & readInterestOp) == 0) {
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }
    

    整個netty啓動完成

  3. InBound與OutBound
    小夥伴搞不清楚他們的執行順序,In是tail節點添加進去的,out是head節點輸出出去的。因此netty處理in的時候是從頭部開始找每一個inbound(一般被通知調用),處理out是從尾部開始找每一個oubound(一般是主動調用out)。
    舉個栗子:

    //1.ServerBootStrap
    .childHandler(new ChannelInitializer<ServerSocketChannel>() {
                    @Override
                    protected void initChannel(ServerSocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                        pipeline.addLast(new StringEncoder(Charset.forName("utf-8")));
                        System.out.println("who am i");
                        pipeline.addLast(new MyService());
                    }
                });
    
    //2. 這是一個InBound  配合 StringDecoder這個Inbound 就形成了 
    //head(out) <=> StringDecoder(in) <=> StringEncoder(out) <=> MyService(in) <=> tail(in)
    //這樣就形成了消息進來先解碼再處理業務, 最後寫出去時候進行編碼。這個設計真的很niubility
    public class MyService extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            //todo 這裏會調用oubound寫出去 所以ChannelHandler添加的順序是有要求的 ~~~~~
            ctx.writeAndFlush("");
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
    
  4. ChannelPromise和ChannelFuture
    ChannelFuture擴展自java的Future接口,能添加監聽器異步獲取執行任務的結果。
    ChannelPromise繼承了ChannelFuture和Promise接口,不但有ChannelFuture的功能還可以設置執行狀態

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章