源码剖析 Netty 服务启动 NIO

如果这个文章看不懂的话 , 建议反复阅读 Netty 与 Reactor

开篇立意。引用网友好的建议。看源码要针对性的看,最佳实践就是,带着明确的目的去看源码。抓主要问题,放弃小问题。主要的逻辑理解了,后面再来看。

源码剖析有一个非常重要的原则 —— 针对性原则,当然,这是我起的名字,意思为一定要有一个明确的目标,针对这个特定的目标死磕到底,跟这个目标无关的内容只要看懂大概逻辑就可以了,不能太深陷,否则容易迷失,特别是开源框架的源码,因为要考虑很多兼容性的问题,会有很多奇奇怪怪的代码,针对这些代码,我们可以略微一瞥,或者直接跳过,如果遇到你感兴趣的问题,但又是跟本次目标无关的,可以先记下来,等本次目标完成了,再把记录的问题归类,重新设置新的目标

何为明确的目标?目标一定是可量化的,不能是含糊的,比如,我要看懂 Netty 所有源码,这就是含糊的目标,比如,我要看懂 Netty 服务启动相关的源码,那就相对明确一些,当然,初期能有这么个目标已经不错了。随着研究的深入,会不断发现新的问题,这些新的问题又可以成为新的目标,只有这样才能不断进步。

/**
 * Echoes back any received data from a client.
 */
public final class EchoServer {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

    public static void main(String[] args) throws Exception {
        // Configure SSL.
        final SslContext sslCtx;
        if (SSL) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        // Configure the server.
        // 1. 声明线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {

            // 2. 服务端引导器
            ServerBootstrap b = new ServerBootstrap();
            // 3. 设置线程池
            b.group(bossGroup, workerGroup)
            // 4. 设置ServerSocketChannel的类型
             .channel(NioServerSocketChannel.class)
            // 5. 设置参数
             .option(ChannelOption.SO_BACKLOG, 100)
                    // 6. 设置ServerSocketChannel对应的Handler,只能设置一个
             .handler(new LoggingHandler(LogLevel.INFO))
                    // 7. 设置SocketChannel对应的Handler
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     // 可以添加多个子Handler
                     //p.addLast(new LoggingHandler(LogLevel.INFO));
                     p.addLast(serverHandler);
                 }
             });
            // 8. 绑定端口
            // Start the server.
            ChannelFuture f = b.bind(PORT).sync();
          //  Netty 的 Channel 跟 Java 原生的 Channel 是否有某种关系?
          //  bind () 是否调用了 Java 底层的 Socket 相关的操作?
          //  Netty 服务启动之后 ChannelPipeline 里面长什么样?
            // 9. 等待服务端监听端口关闭,这里会阻塞主线程
            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();

        } finally {
            // 10. 优雅地关闭两个线程池
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

Netty启动的时候主要是

ChannelFuture f = serverBootstrap.bind(PORT).sync();

今天我们 针对性问题,就是搞清楚 bind () 相关的问题

  1. Netty 的 Channel 跟 Java 原生的 Channel 是否有某种关系?
  2. bind () 是否调用了 Java 底层的 Socket 相关的操作?
  3. Netty 服务启动之后 ChannelPipeline 里面长什么样?
public ChannelFuture bind(int inetPort) {
	return bind(new InetSocketAddress(inetPort));
}

 private ChannelFuture doBind(final SocketAddress localAddress) {

      // key1,初始化并注册什么呢?
        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();
            // key2,绑定什么呢?取决于initAndRegister()中异步执行的快慢,所以不一定到这里,这里可以打一个断点
            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();
                        // key2,绑定什么呢?取决于initAndRegister()中异步执行的快慢,所以不一定到这里,这里可以打一个断点
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }

doBind() 主要干了两件事:
initAndRegister () ,初始化并注册什么呢?
doBind0 () ,到底绑定的是什么?

让我们继续跟进到 initAndRegister() 方法中:

  final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            // key1 ,通过 ChannelFactory 创建一个 Channel ,使用反射的形式创建一个 Channel
            //  反射的类为我们第 4 步中设置的 NioServerSocketChannel.class
            channel = channelFactory.newChannel();

            // key2 ,初始化 Channel ,干了些什么
            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);
        }

        // key3 ,注册 Channel 到哪里?这里有个 group() ,难道是 EventLoopGroup ?
        ChannelFuture regFuture = config().group().register(channel);

        //  失败了,关闭 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;
    }

initAndRegister 主要干了三个事:
1 channelFactory.newChannel () ,通过反射的形式创建 Channel ,而且是无参构造方法, new 的时候做了哪些事儿?
2 init(channel) ,初始化 Channel 的什么?
3 register(channel) ,注册 Channel 到哪里?

这里我们可以学到的设计技巧: 1.构建(工厂模式) 2.初始化 3.业务(例如:注册,或者其他)

因为我们这里使用的是 NioServerSocketChannel ,所以,直接查看它的无参构造方法即可。
补充说明:为什么呢?这里有一个前置知识点。默认你是已经很了解Netty的整个原理了啊。不明白的话。建议反复阅读 Netty 与 Reactor
因为NIO啊,启动是NIO,启动一个建立连接的channel ,然后 该channel 管理连接事件。

// 1.  无参构造方法
    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }

    // 1.1  使用 Java 底层的 SelectorProvider 创建一个 Java 原生的 ServerSocketChannel
    // windows 平台下使用的是 WindowsSelectorProvider ,因为 ServerSocketChannel 是跟操作系统交互的,所以是平台相关的,每个平台下都不一样
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
        // key ,创建 Java 原生 ServerSocketChannel
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }

    // 1.2  有参构造方法,参数是 Java 原生的 ServerSocketChannel
    public NioServerSocketChannel(ServerSocketChannel channel) {
        //  调用父类的构造方法,注意 parent 参数为 null
         // key ,感兴趣的事件为 Accept 事件
        super(null, channel, SelectionKey.OP_ACCEPT);
        //  创建 ChannelConfig
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }
    
    // 1.2.1  调用父类构造方法
    protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent, ch, readInterestOp);
    }

    // 1.2.1.1  调用父类父类的构造方法
    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        //  调用父类的构造方法, parent 为 null
        super(parent);
        // ch 为 Java 原生的 Channel
        this.ch = ch;
        //  感兴趣的事件,这里为 Accept 事件
        this.readInterestOp = readInterestOp;
        try {
        //  将 channel 设置为非阻塞(是不是跟 NIO 案例中的用法一样?!)
            ch.configureBlocking(false);
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {
                logger.warn(
                        "Failed to close a partially initialized socket.", e2);
            }
            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }

    // 1.2.1.1.1  调用父类父类父类的构造方法
    protected AbstractChannel(Channel parent) {
        //  此时 parent 为 null
        this.parent = parent;
        //  赋予一个 id
        id = newId();
        //  赋值了一个 unsafe ,非 Java 的 Unsafe ,而是 Netty 自己的 Unsafe
        unsafe = newUnsafe();
        //  创建 ChannelPipeline
        pipeline = newChannelPipeline();
    }

    // 1.2.1.1.1.1  创建默认的 ChannelPipeline
    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise = new VoidChannelPromise(channel, true);
        // ChannelPipeline 中默认有两个节点, head 和 tail ,且是双向链表
        tail = new TailContext(this);
        head = new HeadContext(this);
        head.next = tail;
        tail.prev = head;
    }

到这里 NioServerSocketChannel的创建过程就完毕了,我们简单总结一下:

        1.Netty 的ServerSocketChannel 会与Java 原生的ServerSocketChannel 绑定在一起;
        2.会注册 Accept事件;
        3.会为每一个 Channel分配一个 id ;
        4.会为每一个 Channel创建一个叫作 unsafe 的东西;
        5.会为每一个 Channel分配一个 ChannelPipeline ;
        6.ChannelPipeline 中默认存在一个双向链表head<=>tail ;好了,

来到了第二步骤, init(channel) 方法:

主流程的第五步:贴出来给大家伙看
在这里插入图片描述
io.netty.bootstrap.ServerBootstrap#init

   @Override
    void init(Channel channel) {

        // 将第5步中设置到ServerBootstrap中的Option设置到Channel的Config中,看上图
        setChannelOptions(channel, newOptionsArray(), logger);

        // 设置一些属性到Channel中,用法与Option一样
        setAttributes(channel, newAttributesArray());

        // 从Channel中取出ChannelPipeline,上面创建的
        ChannelPipeline p = channel.pipeline();

        //  子 Channel 的配置,子 Channel 也就是 SocketChannel
        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);

        // 将 ServerBootstrap 中的 Handler 设置到 ChannelPipeline 的最后
        // ChannelInitializer 的实现原理?
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) {
                final ChannelPipeline pipeline = ch.pipeline();
                //  第 6 步设置的 Handler
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }
                //  同时,又向 ChannelPipeline 的最后添加了一个叫作 ServerBootstrapAcceptor 的 Handler
                //  这是什么写法??有点回调的写法?有点监听器的味道?
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        // 把子 Channel 相关的参数传到这个 Handler 里面,那它是干什么的呢?
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

简而言之:init(channel) 方法整体来说还是比较简单的,就是把 ServerBootstrap 中的配置设置到 Channel 中。

不过依然有几处我们现在可能还不太理解的地方:
ChannelInitializer 的实现原理是什么?
ch.eventLoop().execute() 这是什么写法?
ServerBootstrapAcceptor 是干什么?

我们来到第三步
3 register(channel) ,注册 Channel 到哪里?
好了,我们再来看看 initAndRegister() 方法的最后一个关键步骤, ChannelFuture regFuture = config().group().register(channel); 注册 Channel 到什么地方?

  // key3 ,注册 Channel 到哪里?这里有个 group() ,难道是 EventLoopGroup ?
  ChannelFuture regFuture = config().group().register(channel);

查看源码,可以发现,这里的 group 就是我们的 bossGroup ,所以这里就是调用 bossGroup 的 register(channel)方法。

@Override
public ChannelFuture register(Channel channel) {
	return next().register(channel);
}

这里会调用 next() 方法选择出来一个 EventLoop 来注册 Channel ,里面实际上使用的是一个叫做 EventExecutorChooser 的东西来选择,它实际上又有两种实现方式 —— PowerOfTwoEventExecutorChooser 和 GenericEventExecutorChooser ,本质上就是从 EventExecutor 数组中选择一个 EventExecutor ,我们这里就是 NioEventLoop ,那么,它们有什么区别呢?有兴趣的可以点开它们的源码看看,我简单地提一下,本质都是按数组长度取余数 ,不过, 2的 N 次方的形式更高效。

最后,来到了 EventLoop 的 register(channel) 方法:

io.netty.channel.SingleThreadEventLoop#register(io.netty.channel.Channel)

// io.netty.channel.SingleThreadEventLoop#register(io.netty.channel.Channel)
@Override
public ChannelFuture register(Channel channel) {
	return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
	ObjectUtil.checkNotNull(promise, "promise");
	// key ,调用的是 channel 的 unsafe 的 register() 方法
	promise.channel().unsafe().register(this, promise);
	return promise;
}

可以看到,先创建了一个叫做 ChannelPromise 的东西,它是 ChannelFuture 的子类,暂时先把它当作ChannelFuture 来看待。最后,又调回了 Channel 的 Unsafe 的 register () 方法,这里第一个参数是 this ,也就是NioEventLoop ,第二个参数是刚创建的 ChannelPromise 。

io.netty.channel.AbstractChannel.AbstractUnsafe#register

  @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {

            //  各种检查,可以跳过
            ObjectUtil.checkNotNull(eventLoop, "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;
            }

            // key1 ,将上面传进来的 EventLoop 绑定到 Channel 上  -》  上一步的是 NioEventLoop,当然还有其他的。多好扩展啊
            AbstractChannel.this.eventLoop = eventLoop;

            //  判断当前线程是否跟 EventLoop 线程是同一个
            if (eventLoop.inEventLoop()) {
                // key2 ,调用 register0
                register0(promise);
            } else {
                try {
                    // key2 ,调用 register0 ,实际走的是这里,所以这里需要打个断点
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            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);
                }
            }
        }

这个方法主要干了两件事:
1 把 EventLoop 与 Channel 绑定在一起;
AbstractChannel.this.eventLoop = eventLoop;
2 调用 register0 () 方法;
这里又出现了 eventLoop.execute () 这种写法,先忽略它,专注于主要逻辑。
接着,跟踪到 register0() 方法中:

io.netty.channel.AbstractChannel.AbstractUnsafe#register0

  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;
                // key1 ,调用 doRegister() 方法
                doRegister();
                neverRegistered = false;
                registered = true;

                // key2 ,调用 invokeHandlerAddedIfNeeded()
                //  触发添加 Handler 的回调,其中 pineline.addLast(ChannelInitializer) 的处理就是在这一步完成的
                //  这一步之后 pipeline 里面应该是 head<=>LoggineHandler<=>tail
                //  而 ServerBootstrapAcceptor 还没有加入到 pipeline 中,
                //  因为它设置了使用 EventLoop 的线程执行,当前线程就是 EventLoop 的线程
                //  所以,添加 ServerBootstrapAcceptor 会在当前任务执行完毕才会执行
                // 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.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                //  调用 ChannelPineline 的 fireChannelRegistered() ,实际是调用的各个 ChannelHandler 的 channelRegistered() 方法
                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.
                // Channel 是否已经激活,此时还未绑定到具体的地址,所以还未激活
                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);
            }
        }

这里有两个个非常重要的方法:
1 doRegister () ,一看就是干正事的方法
2 pipeline.invokeHandlerAddedIfNeeded () ,触发添加 Handler 的回调,其中 pineline.addLast (ChannelInitializer)的处理就是在这一步完成的,有兴趣的同学可以跟踪看一下,这一块我们本不详细展开

先来看 doRegister() 方法:

io.netty.channel.nio.AbstractNioChannel#doRegister

 @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                // key ,将 EventLoop 中的 Selector 与 Java 原生的 Channel 绑定在一起,并返回这个 SelectionKey
                //  注意,第三个参数是 this ,代表的是当前这个 Netty 中的 Channel ,我们这里就是 NioServerSocketChannel
                //  它作为 Selection 的 attachment 绑定到 SelectionKey 上,与 JavaChannel 和 Selector 是同一个级别的
                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;
                }
            }
        }
    }

这里其实就一行关键代码,将 Selector 与 Java 原生 Channel 绑定在一起,并将当前 Netty 的 Channel 通过attachment 的形式绑定到 SelectionKey 上,到这里,你可能会有疑问:为什么要把 Netty 的 Channel 当作附件放到 SelectionKey 中呢?

所以,整个注册的过程主要就干了三个事:

  1. 把 Channel 绑定到一个 EventLoop 上;
  2. 把 Java 原生 Channel 、 Netty 的 Channel 、 Selector 绑定到 SelectionKey 中;
  3. 触发 Register 相关的事件;

// 1. io.netty.bootstrap.AbstractBootstrap#doBind0
至此, initAndRegister() 方法内部就分析完成了,我们再来看看另一个重要方法 doBind0() :

    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.
        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());
                }
            }
        });
    }

/ 2. 调用 Channel 的 bind() 方法 io.netty.channel.AbstractChannel#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)

@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
//  调用的是 pipeline 的 bind() 方法
return pipeline.bind(localAddress, promise);
}

// 3. 调用的是 pipeline 的 bind() 方法 io.netty.channel.DefaultChannelPipeline#bind(java.net.SocketAddress, io.netty.channel.ChannelPromise)

@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
//  从尾开始调用,也就是 outbound
return tail.bind(localAddress, promise);
}

// 4. 此时 pipeline 中的 Handler 为 head<=>LoggingHandler<=>ServerBootstrapAcceptor<=>tail ,出站的 pineple 实际为 tail=>LoggingHandler=>head ,下面
我只贴主要代码
// 5. io.netty.handler.logging.LoggingHandler#bind

@Override
public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
if (logger.isEnabled(internalLevel)) {
		logger.log(internalLevel, format(ctx, "BIND", localAddress));
}
ctx.bind(localAddress, promise);
}

// 6. io.netty.channel.DefaultChannelPipeline.HeadContext#bind

@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
//  最后调用的是 HeadContext 这个 Handler 中 unsafe 的 bind() 方法
unsafe.bind(localAddress, promise);
}

// 7. io.netty.channel.AbstractChannel.AbstractUnsafe#bind

@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
//  省略其它代码
boolean wasActive = isActive();
try {
// key ,绑定地址
doBind(localAddress);
} catch (Throwable t) {
		safeSetFailure(promise, t);
		closeIfClosed();
		return;
}
//  成功激活,调用 pipeline.fireChannelActive() 方法
if (!wasActive && isActive()) {
		invokeLater(new Runnable() {
	@Override
	public void run() {
	pipeline.fireChannelActive();
	}
});
}
	//  设置 promise 为成功状态
	safeSetSuccess(promise);
}

// 8. 绕了一圈,最后又回到了 NioServerChannel 的 doBind() 方法 io.netty.channel.socket.nio.NioServerSocketChannel#doBind

@SuppressJava6Requirement(reason = "Usage guarded by java version check")
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
	//  根据不同的 JDK 版本调用不同的方法
	if (PlatformDependent.javaVersion() >= 7) {
	//  我使用的 JDK8 版本,所以走到这里了
	javaChannel().bind(localAddress, config.getBacklog());
} else {
	javaChannel().socket().bind(localAddress, config.getBacklog());
	}
}

可以看到, doBind0() 最后也是通过 Java 原生 Channel 的 bind () 方法来实现的。

最后,我们来总结一下整个服务启动的过程,服务启动主要是通过两个主要的大方法来完成的:

  1. initAndRegister (),初始化并注册什么呢?
channelFactory.newChannel()   
1 通过反射创建一个 NioServerSocketChannel
2Java 原生 Channel 绑定到 NettyChannel3 注册 Accept 事件
4Channel 分配 id
5Channel 创建 unsafe
6Channel 创建 ChannelPipeline(默认是 head<=>tail 的双向链表)

init(channel)
1ServerBootstrap 中的配置设置到 Channel2 添加 ServerBootstrapAcceptor 这个 Handle

register(channel)
1Channel 绑定到一个 EventLoop2Java 原生 ChannelNettyChannelSelector 绑定到 SelectionKey3 触发 Register 相关的事件

2 doBind0 (),到底绑定的是什么?

通过 Java 原生 Channel 绑定到一个本地地址上

留下来的问题有:

ChannelInitializer 是怎么实现的?
ch.eventLoop ().execute () 这种写法是在干什么?
ServerBootstrapAcceptor 是干什么的?
Netty 使用的还是 Java 原生的 Channel,那么,Selector 在哪里用的?

在这里插入图片描述
问题:Netty 的 ServerSocketChannel 会与 Java 原生的 ServerSocketChannel 绑定在一起,这其实就是相当于 用 NioServerSocketChannel 对 java 原生的 ServerSocketChannel 进行了封装吧?

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值