Netty线程模型
Netty简介
Netty是一个高性能,高可扩展性的异步事件驱动的网络应用程序框架,它极大的简化了TCP和UDP客户端和服务器开发等网络编程.
Netty的4个重要内容:
- Reactor线程模型:一种高性能的多线程程序设计思路
- Netty中自己定义的Channel概念:增强版的通道概念
- ChannelPipeline职责链设计模式:事件处理机制
- 内存管理:增强的ByteBuffer缓冲区
Netty整体结构图
从图中可以看出,Netty整体结构包含三个模块:
- 支持Socket等多种传输方式
- 提供了多种协议的编解码实现
- 核心设计包含事件处理模型,API的使用,ByteBuffer的增强
Netty线程模型
为了让NIO处理更好的利用多线程特性,Netty实现了Reactor线程模型,Reactor模型中有4个核心概念:
- Resource资源(请求/任务)
- Synchronous Event Demultiplexer同步事件复用器
- Dispatcher分配器
- Request Handler请求处理器
EventLoopGroup初始化过程
- 构造函数
- 确定线程数量
- new Executor:构建线程执行器
- for->new Child():构建EventLoop
- new EventExecutorChooser
EventLoopGroup可以分为两种,分别是Main和Sub,分别对应reactor和work,如下:
可以打看到两组EventLoopGroup(Main/Sub)处理不同通道的不同事件.
以EchoServer中的EventLoopGroup bossGroup = new NioEventLoopGroup(1);为例,如下:
- 在NioEventLoopGroup通过构造函数构建NioEventLoopGroup
public NioEventLoopGroup(int nThreads) { //nThreads ---> 线程数1 this(nThreads, (Executor) null); }public NioEventLoopGroup(int nThreads, Executor executor) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null this(nThreads, executor, SelectorProvider.provider()); }public NioEventLoopGroup( int nThreads, Executor executor, final SelectorProvider selectorProvider) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null //selectorProvider ---> nio中selector选择器提供程序 this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE); }public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null //selectorProvider ---> nio中selector选择器提供程序 //selectStrategyFactory ---> 默认选择策略工厂 super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()); } - 之后在其父类MultithreadEventLoopGroup中调用构造函数继续构造
顾名思义,既然NioEventLoopGroup继承自MultithreadEventLoopGroup,那么它一定是一个多线程的线程池./** * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...) */ protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null //selectorProvider ---> nio中selector选择器提供程序 ---> args //selectStrategyFactory ---> 默认选择策略工厂 ---> args //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); //如果没有指定线程数量,默认使用CPU核数x2的线程数量 } - 之后再调用MultithreadEventLoopGroup的父类MultithreadEventExecutorGroup中的构造函数继续构造
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null //DefaultEventExecutorChooserFactory ---> 默认事件执行器选择工厂从group中选择合适的eventLoop //selectorProvider ---> nio中selector选择器提供程序 ---> args //selectStrategyFactory ---> 默认选择策略工厂 ---> args //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args); }protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { //nThreads ---> 线程数1 //executor ---> 线程任务执行器 null //DefaultEventExecutorChooserFactory ---> 默认事件执行器选择工厂从group中选择合适的eventLoop //selectorProvider ---> nio中selector选择器提供程序 ---> args //selectStrategyFactory ---> 默认选择策略工厂 ---> args //RejectedExecutionHandlers ---> 默认拒绝处理程序 ---> args //检查设定的线程是否合法 checkPositive(nThreads, "nThreads"); if (executor == null) { //线程创建器不存在,新建一个线程任务执行器,创建NioEventLoop的时候使用 //executor ---> 线程任务执行器 ThreadPerTaskExecutor executor = new ThreadPerTaskExecutor(newDefaultThreadFactory()); } //根据线程数量创建事件执行器数组,事件执行器就是NioEventLoop的父类 children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) { boolean success = false; try { //在这儿目的是创建EventLoop事件执行器 //针对NioEventLoopGroup目的是创建NioEventLoop //那么children最终是一个NioEventLoop数组,那么可见NioEventLoop就是事件执行器 //携带线程任务执行器创建事件执行器,也就是EventLoopGroup中具体的一个 children[i] = newChild(executor, args); success = true; } catch (Exception e) { // --- } finally { // --- } } // --- }/** * Create a new EventExecutor which will later then accessible via the {@link #next()} method. This method will be * called for each thread that will serve this {@link MultithreadEventExecutorGroup}. * */ protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception; - newChild方法实际调用的是NioEventLoopGroup类中的具体实现,其目的是创建一个EventLoop(事件执行器),在这儿实际上是创建的NioEventLoop,不妨继续往下走
/** * 创建EventLoopGroup中具体的事件执行器 * @param executor 线程任务执行器 * @param args 参数[selectorProvider, selectStrategyFactory, rejectedExecutionHandler] * @return 返回事件执行器,在这儿是具体的NioEventLoop * @throws Exception 貌似没有 */ @Override protected EventLoop newChild(Executor executor, Object... args) throws Exception { //executor ---> 线程任务执行器 ThreadPerTaskExecutor //selectorProvider ---> nio中selector选择器提供程序 ---> args 0 //selectStrategyFactory ---> 默认选择策略工厂 ---> args 1 //rejectedExecutionHandler ---> 默认拒绝处理程序 ---> args 2 SelectorProvider selectorProvider = (SelectorProvider) args[0]; SelectStrategyFactory selectStrategyFactory = (SelectStrategyFactory) args[1]; RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) args[2]; EventLoopTaskQueueFactory taskQueueFactory = null; //没有 EventLoopTaskQueueFactory tailTaskQueueFactory = null; //没有 int argsLength = args.length; if (argsLength > 3) { taskQueueFactory = (EventLoopTaskQueueFactory) args[3]; } if (argsLength > 4) { tailTaskQueueFactory = (EventLoopTaskQueueFactory) args[4]; } //创建NioEvent的实际代码,构造器创建 return new NioEventLoop(this, executor, selectorProvider, selectStrategyFactory.newSelectStrategy(), rejectedExecutionHandler, taskQueueFactory, tailTaskQueueFactory); } - 调用NioEventLoop的构造方法创建组中的一个NioEventLoop
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler, EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) { //parent ---> 所属组 NioEventLoopGroup //executor ---> 线程任务执行器 ThreadPerTaskExecutor //selectorProvider ---> nio中selector选择器提供程序 //selectStrategy ---> 选择策略 //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler //taskQueueFactory ---> 任务队列工厂 null //tailTaskQueueFactory ---> tail任务队列工厂 null super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory), rejectedExecutionHandler); this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider"); //设置nio中的任务选择器提供者 this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy"); //设置选择策略 final SelectorTuple selectorTuple = openSelector(); this.selector = selectorTuple.selector; //设置nio中的selector选择器,也就是说在创建NioEventLoop的时候就已经创建了selector this.unwrappedSelector = selectorTuple.unwrappedSelector; //这个不知道干啥的,也是一个选择器 } protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor, boolean addTaskWakesUp, Queue<Runnable> taskQueue, Queue<Runnable> tailTaskQueue, RejectedExecutionHandler rejectedExecutionHandler) { //parent ---> 所属组 NioEventLoopGroup //executor ---> 线程任务执行器 ThreadPerTaskExecutor //addTaskWakesUp ---> 增加任务时是否唤醒 false //taskQueue ---> 任务队列 Queue<Runnable> //tailTaskQueue ---> tail任务队列 Queue<Runnable> //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler super(parent, executor, addTaskWakesUp, taskQueue, rejectedExecutionHandler); tailTasks = ObjectUtil.checkNotNull(tailTaskQueue, "tailTaskQueue"); //设置tail任务队列 } protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, Queue<Runnable> taskQueue, RejectedExecutionHandler rejectedHandler) { //parent ---> 所属组 NioEventLoopGroup //executor ---> 线程任务执行器 ThreadPerTaskExecutor //addTaskWakesUp ---> 增加任务时是否唤醒 false //taskQueue ---> 任务队列 Queue<Runnable> //rejectedExecutionHandler ---> 默认拒绝处理程序 RejectedExecutionHandler super(parent); this.addTaskWakesUp = addTaskWakesUp; //设置在这个事件执行器中添加任务不唤醒 this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS; //设置最大任务数 this.executor = ThreadExecutorMap.apply(executor, this); //设置线程执行器 this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue"); //设置任务队列 this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler"); //设置任务队列超出之后的拒绝策略 } protected AbstractScheduledEventExecutor(EventExecutorGroup parent) { //parent ---> 所属组 NioEventLoopGroup super(parent); } protected AbstractEventExecutor(EventExecutorGroup parent) { //parent ---> 所属组 NioEventLoopGroup this.parent = parent; //设置所属组 }
因此,最终总结下来就是通过EventLoopGroup bossGroup = new NioEventLoopGroup(1);本质上是创建了一个含有1个事件执行器的的事件执行组,那么NioEventLoop又是如何使用的?
EventLoop的启动
EventLoop自身实现了Executor类,当调用execute方法提交任务时,则判断是否启动,未启动则调用内置的executor创建新线程来触发run方法执行.
- execute:请求执行任务
- addTask:增加到任务队列
- 判断是否是EventLoop自身调用
- startThread -> doStartThread
- 使用executor创建新线程执行run
既然NioEventLoop可以认为是一个线程,那么必有其执行方法,只不过NioEventLoop没有具体的实现,而是在其父类SingleThreadEventExecutor中,如下:
@Override
public void execute(Runnable task) {
//task ---> 任务 Runnable
//检查task是否为空
ObjectUtil.checkNotNull(task, "task");
//执行
execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
}
private void execute(Runnable task, boolean immediate) {
//task ---> 任务 Runnable
//immediate ---> 是否立刻执行(无需关注)
boolean inEventLoop = inEventLoop(); //判断execute方法的调用者是不是和NioEventLoop事件执行器在同一个线程
addTask(task); //将任务提交到任务队列taskQueue
if (!inEventLoop) { //不是事件执行器所在线程的重复调用,则允许启动线程
startThread(); //启动线程
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && immediate) {
wakeup(inEventLoop);
}
}
addTask:添加任务到任务队列
/**
* Add a task to the task queue, or throws a {@link RejectedExecutionException} if this instance was shutdown
* before.
*/
protected void addTask(Runnable task) {
//task ---> 任务 Runnable
ObjectUtil.checkNotNull(task, "task"); //判空
if (!offerTask(task)) { //提交任务
reject(task); //未成功执行拒绝策略
}
}
final boolean offerTask(Runnable task) {
//task ---> 任务 Runnable
if (isShutdown()) { //判断线程是否已经关闭
reject(); //已经关闭执行决绝策略
}
return taskQueue.offer(task); //将任务添加到taskQueue,此taskQueue就是在创建NioEventLoop的时候初始化的
}
startThread:启动线程
private void startThread() {
if (state == ST_NOT_STARTED) {
//执行CAS操作将事件执行器状态由ST_NOT_STARTED(1)修改为ST_STARTED(2)
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false; //设置标记
try {
doStartThread(); //启动线程
success = true; //启动成功
} finally {
//未启动则使用CAS操作将事件执行器的状态还原
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
doStartThread:启动线程
private void doStartThread() {
assert thread == null; //判空
//executor这个线程任务执行器是初始化NioEventLoop的时候传进来的,现在在NioEventLoop中执行任务就交给executor来执行
executor.execute(new Runnable() {
@Override
public void run() {
//获取执行execute的线程
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
//在此线程执行run方法
//所以每个EventLoop中的任务都是执行run方法,实际上执行的是NioEventLoop中的run方法,做两件事:
//1.轮询selector.select事件
//2.执行taskQueue中的内容
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {} finally {}
}
}
}
其中执行taskQueue中的内容不用多说,我们重点关注如何轮询selector.select事件
NioEventLoop.processSelectedKeys()
private void processSelectedKeys() {
if (selectedKeys != null) {
processSelectedKeysOptimized();
} else {
//携带选择器中的事件去轮询,这个选择器是初始化NioEventLoop的时候生成的,害为了这个看了两遍前面的
//但是这个选择器和通道绑定后才能生效使用(执行这些事件的时候肯定已经绑定了)
//从绑定了通道的selector中读取事件
processSelectedKeysPlain(selector.selectedKeys());
}
}
NioEventLoop.processSelectedKeysPlain()
/**
* 处理事件
* @param selectedKeys 事件集合
*/
private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
// check if the set is empty and if so just return to not create garbage by
// creating a new Iterator every time even if there is nothing to process.
// See https://github.com/netty/netty/issues/597
if (selectedKeys.isEmpty()) { //没有事件
return;
}
//遍历查询结果
Iterator<SelectionKey> i = selectedKeys.iterator();
//轮询
for (;;) {
//被封装的事件
final SelectionKey k = i.next();
//获取事件对应通道
final Object a = k.attachment();
i.remove(); //从校核中移除事件
if (a instanceof AbstractNioChannel) { //判断是否是netty通道
//处理单个事件
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (!i.hasNext()) {
break;
}
if (needsToSelectAgain) {
selectAgain();
selectedKeys = selector.selectedKeys();
// Create the iterator again to avoid ConcurrentModificationException
if (selectedKeys.isEmpty()) {
break;
} else {
i = selectedKeys.iterator();
}
}
}
}
NioEventLoop.processSelectedKey()
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
//k ---> 被封装的事件
//ch ---> 获取事件对应netty通道
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) { //判断此事件是否有效(无效进入此逻辑关闭unsafe)
final EventLoop eventLoop;
try {
eventLoop = ch.eventLoop(); //获取nio事件执行器
} catch (Throwable ignored) {
// If the channel implementation throws an exception because there is no event loop, we ignore this
// because we are only trying to determine if ch is registered to this event loop and thus has authority
// to close ch.
return;
}
// Only close ch if ch is still registered to this EventLoop. ch could have deregistered from the event loop
// and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
// still healthy and should not be closed.
// See https://github.com/netty/netty/issues/5125
if (eventLoop == this) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
}
return;
}
try {
int readyOps = k.readyOps(); //获取事件类型
// We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
// the NIO JDK channel implementation may throw a NotYetConnectedException.
if ((readyOps & SelectionKey.OP_CONNECT) != 0) { //connect事件主要用于客户端
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
// Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
//write事件在这儿处理
ch.unsafe().forceFlush();
}
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
//accept和read都在这儿进行处理(服务端重点关注)
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
通过查看源代码当前可以知道,EventLoop本身不是一个线程,它的线程时通过线程创建器创建的,之后执行EventLoop中的run方法,去执行任务队列taskQueue中的内容,以及事件选择器Selector.
轮询的机制确实是这样,但是到目前位置还没有看到有通道绑定以及事件的通知,继续吧...
bind绑定端口过程
- bind(端口):AbstractBootStrap
- 创建和初始化channel
- 注册到EventLoop中的Selector上(提交任务到EventLoop执行),注册完成后再继续绑定
- doBind() -> channel.bind
- pipeline.bind(责任链)
- HeadContext.bind
- AbstractUnsafe.bind
- NioServerSocketChannel.doBind
EchoServer
ChannelFuture f = b.bind(PORT).sync();
AbstractBootstrap
/**
* Create a new {@link Channel} and bind it. 创建通道并绑定端口
*/
public ChannelFuture bind(int inetPort) {
//绑定端口的入口方法
return bind(new InetSocketAddress(inetPort));
}
/**
* Create a new {@link Channel} and bind it.
*/
public ChannelFuture bind(SocketAddress localAddress) {
//校验group和channelFactory
validate();
//执行绑定代码
return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化ServerSocketChannel对象,并注册到selector选择器
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel(); //获取初始化的通道
if (regFuture.cause() != null) { //通道没有注册完成
return regFuture;
}
// channel注册完成后再开始绑定端口,防止端口开放了却不能正常处理请求
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
//实际处理端口绑定的方法
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();
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
final ChannelFuture initAndRegister() {
Channel channel = null;
//初始化init
try {
//创建一个netty的通道
channel = channelFactory.newChannel();
//初始化
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);
}
//选择一个事件执行器,将初始化的通道与EventLoop(Selector)进行绑定
//config().group() ---> EventLoopGroup
//故而register应该是EventLoopGroup的方法可以查找
//EventLoopGroup没有查找其父类
ChannelFuture regFuture = config().group().register(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;
}
ChannelFuture regFuture = config().group().register(channel);
config().group()一定返回的是EventLoopGroup,故而register应该是EventLoopGroup的方法可以查找,而EventLoopGroup中的方法是抽象方法,故而应该去找其实现类,我们知道在这儿调用的实际上是一个NioEventLoopGroup,故而应该在NioEventLoopGroup中去查找该方法,未查询到,查找其父类MultithreadEventLoopGroup,从中查询到register方法,如下:
@Override
public ChannelFuture register(Channel channel) {
//next()选择一个合适的NioEventLoop进行绑定 ---> EventLoop(Selector) ---> NioEventLoop
//故而调用NioEventLoop的register方法
//从NioEventLoop中查找到register方法,但是通过参数可以发现一定调用的不是这个方法
//故而应该查询其父类的方法
return next().register(channel);
}
next().register(channel);
next()选择一个合适的EventLoop(NioEventLoop)进行绑定,故而调用NioEventLoop的register方法,从NioEventLoop中查找到register方法,但是通过参数可以发现一定调用的不是这个方法,故而应该查询其父类的方法.最终从NioEventLoop的父类SingleThreadEventLoop中查询到register方法,如下:
@Override
public ChannelFuture register(Channel channel) {
//执行通道绑定到NioEventLoop的相关代码
return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
//NioServerSocketChannel -> NioMessageUnsafe
ObjectUtil.checkNotNull(promise, "promise");
//promise.channel() --=> NioServerSocketChannel
//故而unsafe方法一定是NioServerSocketChannel的方法
//从NioServerSocketChannel中未查询到其方法,从其父类AbstractNioMessageChannel中查询
//从AbstractNioMessageChannel为查询到其方法,从其父类AbstractNioChannel中查询
//最终从AbstractChannel中查询到unsafe方法,是在构造AbstractChannel对象时使用newUnsafe()创建的此值
//因此我们如果要知道unsafe的方法具体的返回值就要从构造方法入手
//首先从NioServerSocketChannel查询newUnsafe方法
//最终从其父类中查询到此方法返回一个NioMessageUnsafe实例
//故而register一定是NioMessageUnsafe的方法
//最终从NioMessageUnsafe的父类AbstractUnsafe中查询到register方法
//故而通道绑定实际调用的还是Channel的register方法
promise.channel().unsafe().register(this, promise);
return promise;
}
promise.channel().unsafe().register(this, promise)
promise.channel()的返回值是一个通道,可以明确知道是NioServerSocketChannel,故而unsafe方法一定是NioServerSocketChannel的方法,从NioServerSocketChannel中未查询到其方法,从其父类AbstractNioMessageChannel中查询,从AbstractNioMessageChannel为查询到其方法,从其父类AbstractNioChannel中查询,最终从AbstractChannel中查询到unsafe方法,是在构造AbstractChannel对象时使用newUnsafe()创建的此值
@Override
public Unsafe unsafe() {
return unsafe;
}
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
因此要知道unsafe具体是什么实例,就要探究newUnsafe()方法,既然是在构造方法中进行初始化的,就要从头开始查找,首先从NioServerSocketChannel查询newUnsafe方法,最终从其父类中查询到此方法返回一个NioMessageUnsafe实例
@Override
protected AbstractNioUnsafe newUnsafe() {
return new NioMessageUnsafe();
}
到此可以明确知晓,实际调用register方法的对象时NioMessageUnsafe对象,因此可以从NioMessageUnsafe中查询register方法,最终从NioMessageUnsafe的父类AbstractUnsafe中查询到register方法,如下:
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
//eventLoop ---> 选择器
//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;
}
AbstractChannel.this.eventLoop = eventLoop;
//判断调用绑定的方法的线程是不是选择器线程,如果不是以线程的方式提交
if (eventLoop.inEventLoop()) {
//实际绑定过程
register0(promise);
} else {
try {
//一旦触发了任务提交,eventLoop就会开始正式执行工作,轮询
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);
}
}
}
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;
doRegister(); //NioChannel中,将Channel与NioEventLoop进行绑定
//到此为止注册完成
neverRegistered = false;
registered = true;
// 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);
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.
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);
}
}
到此为止理清了initAndRegister方法,通道已经绑定,事件开始轮询,之后的事情就是开放端口接收请求了
doBind0(regFuture, channel, localAddress, promise);
这是实际处理端口绑定的方法
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() { //想NioEventLoop提交任务进行端口绑定
//注册完成并且成功
if (regFuture.isSuccess()) {
//绑定
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
//触发一个netty职责链中的绑定事件,由应用层代码发起到底层,属于outBound
return pipeline.bind(localAddress, promise);
}
之后的绑定是netty的职责链需要做的事,到这儿知道端口已经放通就可以了.