Xnio是Jboss对nio的一次优秀的封装网络io框架,相信有研究过undertow源码的同学,在undertow的源码里面或多或少的都有看到xnio的身影
先回忆一下前一篇博文对netty线程模型的概述,先上图:

说白了:就是使用多个线程组,各自分工处理自己的事情,boss线程只负责连接事件,然后把连接好的SocketChannel交给worker线程处理。
在netty中,有说过EventLoop是netty中最最重要的组件,相信在Xnio这种优秀的io框架处理上也会有惊艳的骚操作
首先还是从基本使用定式api上:
在github上down下xnio的源代码,在里面有对xnio使用的demo,关键代码截图如下做讨论用
和分析netty的思路一样,还是先从xnio的重要组件开始
WorkerThread 这个是xnio框架中最最重要的组件
WorkerThread是xnio中完成选择器选择,触发后续组件的入口
类继承图

从继承图上看,WorkerThread继承了Thread的功能和Executor的相关功能
构造器

从构造器上看,WorkerThread持有nio的Selector选择器
重要的方法

从WorkerThread的run方法看,和netty的EventLoop相似,包括了:循环,任务队列,在run方法里面也有看到Selector.select()方法的调用,相信网络事件也是从这里开始的

StreamConnection
xnio抽象的顶层业务接口
首先看一下StreamConnection的构造器:

从类定义上看到StreamConnection包含2个通道:读,写通道(xnio是读写分离的?)
在使用时最多的是:NioSocketStreamConnection,构造器如下:

NioHandle 连接处理器

这个NioHandle功能有点类似于netty的pipeLine
ChannelListener 通信通道监听器

功能有点类似于netty的handler
NioTcpServer 服务器

以上是对xnio核心组件的简单介绍
以下是关于在服务启动过程中的源码分析,会将其中的各组件串联起来,完成
服务启动过程源码分析
在使用jdk的nio作为服务器启动过程中,有几个组件和几个关键动作
组件:Selector,ServerSocketChannel,SelectionKey
动作:
ServerSocketChannel绑定端口号,
ServerSocket注册到Selector上,
selector循环获取注册到上面的感兴趣事件
下面我们依照xnio的启动过程分析上面提到的3个组件和3个动作(xnio也只是对nio的优秀封装而已,相关基准操作一样的会有)
在上面的组件介绍时有提到过:WorkerThread的构造器中有看到持有Selector对象,所以关键是WorkerThrea的构造器调用

如上在使用Xnio获取实例时,是通过SPI机制获取到配置的NioXnio实例的

NioXnio的构造器就是初始化2个SelectorCreator
接着调试第二行:XnioWorker worker = xnio.createWorker(map);

这里就是通过构造者模式创建 XnioWorker,最终调用NioXnio的build方法创建NioXnioWorker

NioXnioWorker就是WorkerThread的容器,里面根据传入的map做配置设置容器大小,启动容器等操作(可以类比netty的EventLoopGroup)

最后调用start()方法:

此时,我们的循环拉取事件动作已经有了,还差:绑定端口,注册感兴趣的事件
这两行代码是:创建事件监听器,通过ChannelListeners包装

端口绑定,并且创建服务器

这行代码就是完成如上所说的功能:绑定端口号,完成服务器的创建
跟踪源代码:
在NioXnioWorker中有创建tcp服务器的入口:

在NioTcpServer的构造器中,有关于ServerSocket的注册动作:
通过调试我们看到,这里的channel是ServerSocketChannel(其实是ServerSocket的实现类),在前面已经说过,WorkerThread里面包含一个Selector,所以此处是将注册动作委托到WorkerThread中进行,最终肯定也是调用ServerSocketChannel.register()完成注册的动作

同时有注意到:在完成注册之后返回的key上,xnio有构建一个NioTcpServerHandle,将该处理器和构建之后的Selection绑定
同时在创建服务器之前有做端口号绑定:

至此:以上过程已经完成了3件事:
端口号绑定,ServerSocketChannel注册到Selector上,做循环拉取事件操作
但是:咱们之前有提到,初始注册的感兴趣事件是0,在nio中是拉取不到连接事件的
所以,真正注册连接事件是在这里:
server.resumeAccepts();

相信这里也和netty一样,是通过改变注册到Selector上的SelectionKey设置感兴趣事件改变的
跟踪代码:


最终将操作委托给了WorkerThread,WorkerThread

在这里,真正将连接事件注册SelectionKey上,此时我们就已经完成了所有的nio相关操作动作了。通过循环拉取事件就可以接收到连接事件,进而读取请求内容,写出数据
发生连接请求时源码分析
我们知道,在nio中,通过循环拉取事件时,如果没有事件时,程序会阻塞在Selector.select()方法上

同样的,我们在WorkerThread的拉取事件出打上断点,等待网络连接事件的到来