// 1. 配置 bossGroup 和 workerGroup
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
final EventLoopGroup workerGroup = new NioEventLoopGroup();
// 2. 创建业务逻辑处理器
final EchoServerHandler serverHandler = new EchoServerHandler();
// 3. 创建并配置服务端启动辅助类 ServerBootstrap
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(serverHandler);
}
});
// 4. 阻塞绑定端口
ChannelFuture f = b.bind(8081).sync();
// 5. 为服务端关闭的 ChannelFuture 添加监听器,用于实现优雅关闭
f.channel().closeFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
});
一、代码执行流程梯形图
/*********************************************** 1. 创建 NioEventLoopGroup ***********************************************/
new NioEventLoopGroup
--> SelectorProvider.provider() -- args
--> new DefaultSelectStrategyFactory() -- args
--> RejectedExecutionHandlers.reject() -- args
--> new DefaultEventExecutorChooserFactory()
--> MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args)
--> ThreadPerTaskExecutor(newDefaultThreadFactory())
--> EventExecutor[] children = new EventExecutor[nThreads]
--> children[i] = newChild(executor, args)
--> NioEventLoopGroup.newChild(Executor executor, Object... args)
--> DefaultSelectStrategyFactory.newSelectStrategy()
--> SelectStrategy INSTANCE = new DefaultSelectStrategy()
--> new NioEventLoop(NioEventLoopGroup parent,
Executor executor,
SelectorProvider selectorProvider,
SelectStrategy strategy,
RejectedExecutionHandler rejectedExecutionHandler)
--> SingleThreadEventExecutor(EventExecutorGroup parent,
Executor executor,
boolean addTaskWakesUp,
int maxPendingTasks,
RejectedExecutionHandler rejectedHandler)
--> Queue taskQueue = NioEventLoop.newTaskQueue(int maxPendingTasks)
--> PlatformDependent.newMpscQueue()
--> SingleThreadEventLoop.Queue tailTasks = NioEventLoop.newTaskQueue(int maxPendingTasks)
--> Selector selector = provider.openSelector() // 简化,netty 有优化过
--> EventExecutorChooserFactory.EventExecutorChooser chooser = chooserFactory.newChooser(children)
--> new PowerOfTwoEventExecutorChooser(executors)
最终的 NioEventLoopGroup 实例:
-- EventExecutor[] children = new EventExecutor[1](实例是 NioEventLoop)
-- Thread thread = null // NIO 线程
-- Executor executor = new ThreadPerTaskExecutor(new DefaultThreadFactory)// 线程创建器
-- Selector selector = 根据系统创建不同的 selector // selector 选择器
-- SelectedSelectionKeySet selectedKeys // 存储被选中的 SelectionKey 列表
-- SelectionKey[] keys
-- SelectStrategy selectStrategy = new DefaultSelectStrategy()
-- int ioRatio = 50 // selected和队列中任务的执行时间比例
-- Queue taskQueue = new MpscUnboundedArrayQueue(1024) // 任务队列
-- Queue tailTasks = new MpscUnboundedArrayQueue(1024)
-- PriorityQueue> scheduledTaskQueue = null
-- RejectedExecutionHandler rejectedExecutionHandler // 回绝策略
-- EventExecutorGroup parent = this 即 NioEventLoopGroup 实例 // 所属的 NioEventLoopGroup
-- DefaultEventExecutorChooserFactory.PowerOfTwoEventExecutorChooser // 线程选择器:从children中选择一个EventExecutor实例
-- EventExecutor[] children = new EventExecutor[1]
/*********************************************** 2. 创建并设置 ServerBootstrap ***********************************************/
new ServerBootstrap()
--> Map, Object> options = new LinkedHashMap<>()
--> Map, Object> attrs = new LinkedHashMap<>()
--> Map, Object> childOptions = new LinkedHashMap<>()
--> Map, Object> childAttrs = new LinkedHashMap<>()
--> ServerBootstrapConfig config = new ServerBootstrapConfig(this)
// 设置 group
ServerBootstrap.group(bossGroup, childGroup)
--> EventLoopGroup group = bossGroup
--> EventLoopGroup childGroup = childGroup
// 设置 channel
ServerBootstrap.channel(NioServerSocketChannel.class)
--> ChannelFactory channelFactory = new ReflectiveChannelFactory(Class extends T> clazz) // 设置channel创建工厂,反射建立 channel
// 设置 option
ServerBootstrap.option(ChannelOption.SO_BACKLOG, 100)
--> Map, Object> options.put
// 设置 handler
ServerBootstrap.handler(new LoggingHandler(LogLevel.INFO))
--> ChannelHandler handler = LoggingHandler实例
// 设置 childHandler
ServerBootstrap.childHandler(new ChannelInitializer{})
--> ChannelInitializer channelInitializer = new ChannelInitializer(){}
--> ChannelHandler childHandler = channelInitializer
/*********************************************** 3. bind ***********************************************/
ServerBootstrap.bind(int inetPort)
--> AbstractBootstrap.doBind(SocketAddress localAddress)
--> ChannelFuture regFuture = initAndRegister()
/********** 3.1 创建 NioServerSocketChannel *********/
--> Channel channel = channelFactory.newChannel() // channelFactory=ReflectiveChannelFactory
--> new NioServerSocketChannel()
--> newSocket(SelectorProvider provider)
--> provider.openServerSocketChannel() // 创建 java.nio.channels.ServerSocketChannel
--> NioServerSocketChannel(ServerSocketChannel channel)
--> AbstractChannel(Channel parent) // parent=null
--> CloseFuture closeFuture = new CloseFuture(this)
--> ChannelId id = DefaultChannelId.newInstance()
--> Unsafe unsafe = new NioMessageUnsafe() // 每一个 Channel 都有一个 Unsafe 对象
--> ChannelOutboundBuffer outboundBuffer = new ChannelOutboundBuffer(AbstractChannel.this)
--> List
总结:
- 创建 NioEventLoopGroup
- 创建一个 EventExecutor[],并且实例化其内的每一个元素为 NioEventLoop(EventExecutor 是 NioEventLoop 的子类)
- 每个 NioEventLoop 都包含一条线程 Thread,Netty 默认是 FastThreadLocalThread,此处为 null,后续在执行注册任务的时候,会赋值并且开启线程(每个 NioEventLoop 都包含事先被创建好的 ThreadPerTaskExecutor,该线程执行器用于线程 FastThreadLocalThread 的创建)
- 每个 NioEventLoop 都包含一个 Selector,用于死循环进行 NIO 感兴趣事件的监听
- 每个 NioEventLoop 都包含一个 taskQueue,用于存放非 NioEventLoop 线程提交的任务
- 每个 NioEventLoop 都包含一个 scheduledTaskQueue,用于存放定时任务(例如连接超时任务),此处为 null - 懒创建
- 每个 NioEventLoop 都包含一个 ioRatio,用于决定 IO 事件和队列任务的执行时间比例
- 创建 NioEventLoop 选择器,用于后续从 EventExecutor[] 选择一个 NioEventLoop
- 创建并设置 ServerBootstrap
- options、attrs、handler 都是针对 ServerSocketChannel 起作用的;
- childOptions、childAttrs、childHandler 都是针对由 ServerSocketChannel.accept() 出来的 SocketChannel 起作用的
- 设置 channel 时,创建了 ReflectiveChannelFactory,用于反射创建 NioServerSocketChannel
- 绑定操作
- 使用 ReflectiveChannelFactory 反射创建 NioServerSocketChannel
- 创建 java.nio.channels.ServerSocketChannel,NioServerSocketChannel 是其包装类
- 为 NioServerSocketChannel 设置唯一ID
- 为 NioServerSocketChannel 设置 Unsafe 实例(服务端是 NioMessageUnsafe),Unsafe 是真正的进行底层 IO 操作的类 - 每一个 Channel 都有一个 Unsafe 对象
- 为 NioServerSocketChannel 设置 ChannelPipeline 对象 - 每一个 Channel 都有一个 ChannelPipeline 对象,每一个 ChannelPipeline 都包含一条由 ChannelHandlerContext 组成的双向链表(这条双向链表至少有两个节点 HeadContext 和 TailContext),每个 ChannelHandlerContext 内部都包裹着一个 ChannelHandler。
- 设置 java.nio.channels.ServerSocketChannel 为非阻塞
- 记录感兴趣事件为 ACCEPT 事件
- 初始化 NioServerSocketChannel 属性并添加 acceptorInitializer
- 设置 options、attrs 到 NioServerSocketChannel
- 创建 acceptorInitializer 并添加其到 NioServerSocketChannel 的 ChannelPipeline 对象中,此时的 ChannelPipeline 链是
HeadContext <-> acceptorInitializer <-> TailContext
,acceptorInitializer 包含一个 ServerBootstrapAcceptor
- 执行注册:此时启动Nio线程 + 注册 channel 到 selector
- 使用 NioEventLoopGroup 的线程选择器从 bossGroup 中选出一个 NioEventLoop
X
- 最终调用 NioMessageUnsafe 执行注册,由于当前执行线程不是当前 eventLoop 的那条 NioEventLoop 线程,所以创建注册任务,并加入
X
的 taskQueue 中,然后创建线程,赋值给X
的 thread 属性,之后启动线程,执行 NIO 死循环- NIO 死循环会按照 ioRatio 计算出来的时间比分别执行 “处理 NIO 感兴趣的事件” 和 “处理队列中的任务”(会将到期的 scheduledTaskQueue 中的 task 加入 taskQueue,之后统一从 taskQueue pollTask),此时会执行注册任务
- 注册任务:
- 将 NioServerSocketChannel 中的 java.nio.channels.ServerSocketChannel 注册到
X
的 Selector 上,选择键为0(此时不监听任何事件),attachment 为 NioServerSocketChannel 本身- pipeline.invokeHandlerAddedIfNeeded() 会执行到 acceptorInitializer,首先执行其 initChannel,此时创建
ServerBootstrapAcceptor
并添加到 ChannelPipeline,如下HeadContext <-> acceptorInitializer <-> ServerBootstrapAcceptor <-> TailContext
,最后删除 acceptorInitializer,最终的 ChannelPipeline 链是HeadContext <-> ServerBootstrapAcceptor <-> TailContext
(其中,ServerBootstrapAcceptor 中存储着 childOptions、childAttrs、childHandler 以及 workerGroup,后续有客户端进行连接时,服务端会监听到 ACCEPT 事件,进而会使用 ServerBootstrapAcceptor 做一些逻辑)- 注册完毕之后 执行 channelRegister() 事件
- 绑定
- 与注册操作一样绑定操作也是非当前 Channel 所属的 NioEventLoop 线程发起的,所以也要封装为任务,加入到
X
的 taskQueue 中(每加入队列一个任务,都会做一次 selector.wakeup 操作,起到及时执行任务的作用)
- 绑定任务的内容:pipeline.fireChannelActive()
- 执行 channelActive() 事件
- 为 NioServerSocketChannel 设置感兴趣的监听键为创建 NioServerSocketChannel 时所存储的 ACCEPT 事件
注意:
- bind 一定要发生在 register 之后,但是 Netty 中所有的执行都是异步的,register 也不例外,那么怎么保证 bind 一定发生在 register 之后,Netty 使用为 regsiter 添加执行完成的回调监听器,在该监听器中完成 bind 操作。
- 一个 Channel 的事情只能由一个 NioEventLoop 来操作,所以 EventExecutor#inEventLoop() 不是判断当前线程是不是 NioEventLoop 中的那条线程,而是判断是否是当前所操作的 Channel 所属的 NioEventLoop 的那条线程。在 accept 的操作过程中,调用注册的线程是 NioServerSocketChannel 的那条线程,而注册的 Channel 是 SocketChannel,所以还是要包装成任务,添加到 SocketChannel 所属的那条 NioEventLoop 中。
- 当 j 是 2的n次方的时候,i % j == i &(j-1),后者效率更高,PowerOfTwoEventExecutorChooser 是后者,也是默认;GenericEventExecutorChooser 是前者。