Netty--核心模块组件 BootStrap ServerBootstrap(二)

在(一)中叙述了ServerBootStarp.bind()方法的initAndRegister()
本文将讲述在AbstractBootstarp.doBind()中的第二个核心方法 doBind0()

AbstractBootstrap.doBind0()
 private static void doBind0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress localAddress, final ChannelPromise promise) {
	// channel = NioServerSokcetChannel
      	
        
		
			1、ChannelFuture接口。因为在Netty中所有的I/O操作都是异步的,所以在我们注册NIOServerSocketChannel的时候我们不必要等待是否注册成功再执行下一步的操作,这是Netty通过这个对象(异步操作对象),可以在NIOServerSocketChannel是否注册成功后返回给我们信息。以方便我们在以后调用。这里有四种状态
						
						                     +---------------------------+
				 *                                      | 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      |
				 *                                      +---------------------------+
	
	这里调用的与channel相关联的eventLoop中的线程池提交绑定端口的任务。接下来就是执行runAllTasks中的任务。
	第二个任务就是执行为channel绑定端口号了。	

	channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                    channel.bind(localAddress,promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }
channel.bind()

首先执行AbstractChannel的bind
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }

执行DefaultChannelPipeline的bind  这里是执行咱们在初始化DefaultChannelPipeline 时 自初始化的尾节点的bind()
 public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }
    
执行 AbstractChannelHandlerContext.bind()
 public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }
        if (isNotValidPromise(promise, false)) {
            // cancelled
            return promise;
        }
		
		// 在DefaultChannelPipeline 中查找Netty初始化的执行绑定端口操作的handler
		// ServerBootstrap$ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter
        final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeBind(localAddress, promise);
        } else {
            safeExecute(executor, new Runnable() {
                @Override
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null);
        }
        return promise;
    }

AbstractChannelHandlerContext.invokeBind()
	private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
        if (invokeHandler()) {
            try {
                ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
            } catch (Throwable t) {
                notifyOutboundHandlerException(t, promise);
            }
        } else {
            bind(localAddress, promise);
        }
    }

DefaultChannelPipeline.bind()
/**
	这里的unsafe 就是我们前面初始化的NioMessageUnsafe对象
*/

 @Override
 public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
 	// 这里是调用NioMessageUnsafe的父类AbstractUnsafe的bind方法
    unsafe.bind(localAddress, promise);
 }

AbstractChannel.AbstractUnsafe.bind()
 public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            boolean wasActive = isActive();
            
     可以看到,这里最终的方法就是 doBind  方法,执行成功后,执行通道的 fireChannelActive 的 方法,告诉所有的 handler ,已经成功绑定。
            try {
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }

            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }

NioServerSocketChannel.doBind()
最终 doBind 就会追踪到 NioServerSocketChannel 的 doBind, 说明 Netty 底层使用的是 Nio
 protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }

回到 bind 方法(alt+v),最后一步:safeSetSuccess(promise),告诉 promise 任务成功了。其可以执行监听器的
方法了。到此整个启动过程已经结束了。然后就是继续循环执行runAllTasks中的任务了。

Netty启动过程整理

  1. 创建两个NioEventLoopGroup 线程池。默认大小为CPU核数*2
  2. ServerBootStarp 的 父类 AbstractBootstarp 将group属性设置为BossGroup。ServerBootStarp 将childGroup 属性设置为 WorkerGroup。
  3. 通过bind()方法启动,内部重要方法initAndRegister() 和 doBind()方法
  4. initAndRegister 方法会创建反射NIOServerSocketChannel 及其相关的NIO的对象,pipeline(DefauleChannelPipeline) unsafe(NioMessageUnsafe) 同时也为pipeline 创建head 和 tail节点。
  5. doBind() 方法中调用 doBind0() 方法,该方法会 调用 NioServerSocketChannel 的 doBind() 方法对 JDK 的 channel 和端口进行绑定,完成 Netty 服务器的所有启动,并开始监听连接事件.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值