五 Netty 学习:服务端启动核心流程源码说明( 二 )

其中provider.openServerSocketChannel()就是调用底层 JDK 的 API,获取了 JDK 底层的java.nio.channels.ServerSocketChannel
通过super(null, channel, SelectionKey.OP_ACCEPT);一路跟踪进去,进入AbstractNioChannel中,
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {super(parent);……ch.configureBlocking(false);……}关键代码是ch.configureBlocking(false) , 设置 I/O 模型为非阻塞模式 。
通过super(parent)跟踪上去,
protected AbstractChannel(Channel parent) {this.parent = parent;id = newId();unsafe = newUnsafe();pipeline = newChannelPipeline();}其中 id 是 Netty 中每条 Channel 的唯一标识 。
以上就是服务端 Channel 的创建过程 。
接下来是服务端 Channel 的初始化过程,回到AbstractBootstrap.initAndResgister()方法
……final ChannelFuture initAndRegister() {……// channel 的新建channel = channelFactory.newChannel();// channel 的初始化init(channel);……}……其中的init(channel)方法就是服务端的 Channel 的初始化过程,Debug 进入,发现是调用了ServerBootstrap.init(channel)方法,
@Overridevoid init(Channel channel) {……// 设置一些 Channel 的属性和配置信息……p.addLast(new ChannelInitializer<Channel>() {@Overridepublic void initChannel(final Channel ch) {final ChannelPipeline pipeline = ch.pipeline();ChannelHandler handler = config.handler();if (handler != null) {pipeline.addLast(handler);}ch.eventLoop().execute(new Runnable() {@Overridepublic void run() {pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));}});}});}其核心代码如上 , 主要用于定义服务端启动过程中需要执行哪些逻辑 。主要分为两块:

  1. 一块是添加用户自定义的处理逻辑到服务端启动流程 。
  2. 另一块是添加一个特殊的处理逻辑,ServerBootstrapAcceptor 是一个接入器,接受新请求 , 把新的请求传递给某个事件循环器 。
以上就是服务端的 Channel 的初始化过程 。接下来是服务端 Channel 的注册 Selector 的过程 。
@Overrideprotected void doRegister() throws Exception {boolean selected = false;for (;;) {try {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;}}}}在这个步骤中 , 我们可以看到关于 JDK 底层的操作
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);首先拿到在前面过程中创建的 JDK 底层的 Channel , 然后调用 JDK 的 register() 方法,将 this 也即 NioServerSocketChannel 对象当作 attachment 绑定到 JDK 的 Selector 上 , 这样后续从 Selector 拿到对应的事件之后,就可以把 Netty 领域的 Channel 拿出来 。
接下来是服务端绑定端口的逻辑,见AbstractBootstrap中的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() {@Overridepublic void run() {if (regFuture.isSuccess()) {channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);} else {promise.setFailure(regFuture.cause());}}});}图例本文所有图例见:processon: Netty学习笔记
代码hello-netty
更多内容见:Netty专栏
参考资料跟闪电侠学 Netty:Netty 即时聊天实战与底层原理
深度解析Netty源码
【五 Netty 学习:服务端启动核心流程源码说明】

推荐阅读