上篇博客已经讲完了bind()
方法,但是bind()
方法中还有两个部分没有讲,一个是dobind0()
方法,还有一个就是在执行register()
的方法的时候开启了一个线程执行register0()
方法,这个线程开启的方法就是我们主要讲的。下面就让我们代码重现吧。具体的代码如下所示:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("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;
}
//promise=DefaultChannelPromise
//eventLoop=SingleThreadEventLoop
//this.eventLoop=NioEventLoop==>SingleThreadEventLoop.this
AbstractChannel.this.eventLoop = eventLoop;
//他们最终都调用了register0 eventLoop.inEventLoop()的作用?
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
System.out.println("register0");
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);
}
}
}
}
}
上面的代码会执行到eventLoop.execute()
方法,我们继续重现。具体的代码如下:
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
//调用doStartThread方法启动事件轮询后此方法返回true
boolean inEventLoop = inEventLoop();
//将任务加入线程队列
addTask(task);
//判断当前执行此任务的线程是否是SingleThreadEventExecutor
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 && wakesUpForTask(task)) {
//唤醒阻塞的selector
wakeup(inEventLoop);
}
}
}
上面走来会将刚才的register0()
方法添加到任务队列taskQueue
中去,然后判断当前执行此任务的线程是否是SingleThreadEventExecutor
,很明显是,这个就开始调用startThread();
方法来启动线程了。具体的代码如下:
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
private void startThread() {
if (state == ST_NOT_STARTED) {
//尝试将ST_NOT_STARTED设置为ST_STARTED
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false;
try {
doStartThread();
success = true;
} finally {
//如果执行doStartThread()出现异常 将STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED回滚
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
}
上面的代码直接通过CAS
操作将线程的状态从ST_NOT_STARTED
改成ST_STARTED
,然后调用doStartThread();
具体的代码如下:
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
private void doStartThread() {
assert thread == null;
//真正的启动线程
executor.execute(new Runnable() {
@Override
public void run() {
//将此线程保存起来
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (;;) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
// Run all remaining tasks and shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
cleanup();
} finally {
// Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
// the future. The user may block on the future and once it unblocks the JVM may terminate
// and start unloading classes.
// See https://github.com/netty/netty/issues/6596.
FastThreadLocal.removeAll();
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.countDown();
if (logger.isWarnEnabled() && !taskQueue.isEmpty()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
}
上面的executor.execute();
通过线程工厂启动了一个线程去执行下面的代码,我们今天主要分析就是下面的这段代码。这个时候将当前线程赋值给属性thread
这个开启线程中最核心的方法就是SingleThreadEventExecutor.this.run();
也是我们今天重点要讲的方法,我们继续跟进相应的代码,具体的代码如下:
public final class NioEventLoop extends SingleThreadEventLoop {
//事件循环
@Override
protected void run() {
for (;;) {
try {
try {
//hasTasks() 若taskQueue or tailTasks任务队列中有任务 返回false 没有则返回true
//有任务返回selectNow的返回值 没任务返回-1
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
// fall-through to SELECT since the busy-wait is not supported with NIO
case SelectStrategy.SELECT:
//首先轮询注册到reactor线程对应的selector上的所有的channel的IO事件
//wakenUp 表示是否应该唤醒正在阻塞的select操作,netty在每次进行新的loop之前,都会将wakeUp 被设置成false,标志新的一轮loop的开始
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
// fall through
default:
}
} catch (IOException e) {
// If we receive an IOException here its because the Selector is messed up. Let's rebuild
// the selector and retry. https://github.com/netty/netty/issues/8566
rebuildSelector0();
handleLoopException(e);
continue;
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
//2.处理产生网络IO事件的channel
processSelectedKeys();
} finally {
// Ensure we always run tasks.
final long ioTime = System.nanoTime() - ioStartTime;
//3.处理任务队列
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
// Always handle shutdown even if the loop processing threw an exception.
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
}
上面的hasTasks()
是若taskQueue
或tailTasks
任务队列中有任务返回true
没有则返回false
,selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())
方法是有任务就返回selectNow
的返回值 没任务返回-1,由于这儿已经添加了一个register0()
的任务,所以这儿的返回值不是下面的任何一种策略,然后直接进入default
,这个switch就直接结束。然后下面的判断ioRatio
是否等于100,由于第一次的初始化为50,所以这个if
判断是不会进入,会直接进入else
,这个时候会先执行processSelectedKeys();
方法。点进去看了一下,发现是处理产生的网络IO事件的channel
,我们这儿先略过,我们今天的重点不是它,这个会在后续的博客中讲到。我们直接看runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
方法,我们跟进去查看相应的代码,具体的代码如下:
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
/**
* 轮询任务队列中的所有任务,并通过{@link Runnable#run()}方法运行它们。此方法停止运行
* 任务队列中的任务,如果运行时间超过{@code timeoutNanos},则返回。
*/
protected boolean runAllTasks(long timeoutNanos) {
//从scheduledTaskQueue转移定时任务到taskQueue
fetchFromScheduledTaskQueue();
Runnable task = pollTask();
if (task == null) {
//尝试在获取一次 如果有就执行
afterRunningAllTasks();
return false;
}
//计算本次任务循环的截止时间
final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
long runTasks = 0;
long lastExecutionTime;
//循环执行任务 到了指定时间 或者 没有任务执行了就会直接结束
for (;;) {
afeExecute(task);
runTasks ++;
//每64个任务检查一次超时,因为nanoTime()比较耗时
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
task = pollTask();
if (task == null) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
break;
}
}
afterRunningAllTasks();
this.lastExecutionTime = lastExecutionTime;
return true;
}
}
上面的死循环就是执行任务队列taskQueue
中的任务,两种情况会结束这个循环,第一种就是到了指定的时间,第二种就是没有任务执行了,就会结束这个死循环,但是这儿是有任务的。这儿的任务是register0()
,我们找到对应的方法,继续跟进去,查看相应的代码,具体的代码如下:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
// 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
// 调用在eventLoop之外
//promise=DefaultChannelPromise
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
//调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法 选择器看不同操作系统
doRegister();
neverRegistered = false;
registered = true;
// 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
// 用户可能已经通过ChannelFutureListener中的管道触发事件。
// 会执行handlerAdded方法
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//会执行channelRegistered
pipeline.fireChannelRegistered();
// 只有当通道从未被注册时,才激活该通道。这可以防止解雇
// 如果取消注册并重新注册通道,则多个通道将激活。
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
// 这样我们就可以处理入站数据。
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// 直接关闭通道,避免FD泄漏。
closeForcibly();
loseFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
}
上面的代码走来会调用doRegister();
方法,大概的意思就是调用java
原生channel
的register
的方法,并且将子类包装好的selector
传入了进去,具体的代码如下:
public abstract class AbstractNioChannel extends AbstractChannel {
//注册核心方法
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
//javaChannel() ==> ServerSocketChannel 通过反射创建出来nio底层channel
//调用Nio底层将ServerSocketChannel注册到selector上
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
//强制选择器现在选择,因为“已取消”的SelectionKey可能仍然是
//缓存并没有删除,因为还没有调用Select.select(..)操作。
eventLoop().selectNow();
selected = true;
} else {
//我们之前在选择器上强制执行了select操作,但是SelectionKey仍然缓存
//不管什么原因。JDK错误?
throw e;
}
}
}
}
}
上面的doRegister()
方法执行完,然后返回到原来的调用的地方,为了防止代码忘记,我们这儿再次贴出相应的代码,具体的代码如下:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
// 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
// 调用在eventLoop之外
//promise=DefaultChannelPromise
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
//调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法 选择器看不同操作系统
doRegister();
neverRegistered = false;
registered = true;
// 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
// 用户可能已经通过ChannelFutureListener中的管道触发事件。
// 会执行handlerAdded方法
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//会执行channelRegistered
pipeline.fireChannelRegistered();
// 只有当通道从未被注册时,才激活该通道。这可以防止解雇
// 如果取消注册并重新注册通道,则多个通道将激活。
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
// 这样我们就可以处理入站数据。
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// 直接关闭通道,避免FD泄漏。
closeForcibly();
loseFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
}
然后就会执行pipeline.invokeHandlerAddedIfNeeded();
方法,我们继续跟进相应的代码,具体的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
// 我们现在注册到EventLoop。是时候调用通道处理程序的回调了,
// 这些都是在注册之前添加的。
callHandlerAddedForAllHandlers();
}
}
}
firstRegistration
默认值是true
,所以这个if
判断会直接进,然后将firstRegistration
值改成false
,最后再去执行callHandlerAddedForAllHandlers();
,我们继续跟进该方法,具体的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
// 该通道本身已注册。
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
this.pendingHandlerCallbackHead = null;
}
//这必须发生在synchronized(…)块之外,否则handlerAdded(…)可能在while中被调用
//如果handleradd(…)试图从外部添加另一个处理程序,则会持有锁,从而产生死锁
// EventLoop。
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
}
这儿的pendingHandlerCallbackHead
属性在之前执行addLast()
添加了一个new PendingHandlerAddedTask(ctx)
而这儿目前只有一个task
的任务,我们循环这个task
,然后执行task.execute();
方法,这儿执行的是PendingHandlerAddedTask(ctx)
类中的execute()
方法,我们继续跟进去,对应的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
private final class PendingHandlerAddedTask extends PendingHandlerCallback {
@Override
void execute() {
//ctx.executor(); 当ctx中的executor为空的时候 获取NioEventLoop
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
logger.warn(
"Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
executor, ctx.name(), e);
}
remove0(ctx);
ctx.setRemoved();
}
}
}
}
}
这个时候之前已经保存了thread
的信息,所以这儿判断如果不是原来的线程执行的话,这个判断就不会成立。如果不是又会将当前的任务添加到taskQueue
中去,这儿的判断是会成立的,我们会调用callHandlerAdded0(ctx);
方法,我们继续跟进相应的代码,具体的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.callHandlerAdded();
} catch (Throwable t) {
boolean removed = false;
try {
remove0(ctx);
ctx.callHandlerRemoved();
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
if (removed) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; removed.", t));
} else {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; also failed to remove.", t));
}
}
}
}
这个时候会直接调用ctx.callHandlerAdded();
方法,我们继续跟进相应的代码。
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {
final void callHandlerAdded() throws Exception {
// We must call setAddComplete before calling handlerAdded. Otherwise if the handlerAdded method generates
// any pipeline events ctx.handler() will miss them because the state will not allow it.
//判断handlerState等于1 并且设置handlerState为2
if (setAddComplete()) {
handler().handlerAdded(this);
}
}
}
这个时候setAddComplete()
方法通过死循环的方式和CAS
操作将handlerState
改成了ADD_COMPLETE
表示添加完成,这个时候会继续执行handler().handlerAdded(this);
这个handler()
方法获取是在ServerBootstrap
中添加那个匿名内部类,也就是ChannelInitializer
,这个时候调用的是ChannelInitializer
中的handlerAdded(this);
方法,我们继续跟进去看看,具体的代码如下:
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
//对于当前的DefaultChannelPipeline实现,这应该总是正确的。
//在handlerAdded(…)中调用initChannel(…)的好处是没有订单
//如果一个通道初始化器将添加另一个通道初始化器,会让人感到惊讶。这是所有的处理程序
//将按预期顺序添加。
if (initChannel(ctx)) {
// We are done with init the Channel, removing the initializer now.
removeState(ctx);
}
}
}
}
走来会先判断这个通道有没有注册,很明显这儿已经注册好了,然后这儿会执行initChannel(ctx)
方法,我们打开对应的代码,具体的代码如下:
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) { // Guard against re-entrance.
try {
//我们写的ChannelInitializer.initChannel的方法 将在这里被调用
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
//删除此节点
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}
}
这个时候会调用initChannel((C) ctx.channel());
方法,由于我们这儿添加的NettyTestHendler
类没有实现ChannelInitializer
这个类,所以调用的是下面这个方法,就是调用到ServerBootstrap
类中的添加的匿名内部类中的方法,你会发现在调用这个方法后,finally
中有个删除当前节点的操作,所以说ChannelInitializer
这个节点是个特殊的节点,因为它只用来添加你自定义的pipeline
,添加完成后,这个对应ChannelInitializer
就会移除,具体的代码如下:
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
//System.out.println(ch==channel); true
final ChannelPipeline pipeline = ch.pipeline();
//System.out.println(pipeline==p); true
//config.handler()=自己创建的new ChannelInitializer<ServerSocketChannel>()
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
//System.out.println("执行了");
//bossGroup将客户端连接转交给workerGroup
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
上面的方法会取出我们手动添加的pipeline
,这个时候我们通过对应的方法addLast(handler);
,将它添加到pipeline
中去,这儿有一点和之前的调用不一样,我们继续分析,具体的代码如下:
public class DefaultChannelPipeline implements ChannelPipeline {
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
//group=null
//name =null
//handler=new ChannelInitializer<Channel>
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
//检查添加
checkMultiplicity(handler);
//filterName(name, handler) 当我们没有指定名字时 给我们默认生成一个
//new DefaultChannelHandlerContext()
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
//判断handlerState属性等于0 并且设置为1 置为待处理状态
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
//返回NioEvenGroup
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
}
上面的第一个if
判断是不会进的,因为registered
已经在前面的一个方法将其改成true
了,这个时候第二个判断,由于当前的thread
存的是NioEventLoop
,但是这儿是否,所以下面那个判断也不会进的。最后就会执行callHandlerAdded0(newCtx);
方法,我们会发现调用的链路是一样的,最终会执行到我自己写的handlerAdded
方法中去。如果对应的handlerAdded
没有写,就会调用父类的ChannelInitializer
中的handlerAdded
这个时候又会重新调用一下你继承ChannelInitializer
的子类中的initChannel
方法。至此pipeline.addLast(handler);
执行完成,我们继续回到原来的代码,继续跟进下去。具体的代码如下:
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
//System.out.println(ch==channel); true
final ChannelPipeline pipeline = ch.pipeline();
//System.out.println(pipeline==p); true
//config.handler()=自己创建的new ChannelInitializer<ServerSocketChannel>()
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
//System.out.println("执行了");
//bossGroup将客户端连接转交给workerGroup
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
这个时候会执行ch.eventLoop().execute()
方法,这个方法又是将当前的任务添加到任务队列,对应的代码如下:
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
//调用doStartThread方法启动事件轮询后此方法返回true
boolean inEventLoop = inEventLoop();
//将任务加入线程队列
addTask(task);
//判断当前执行此任务的线程是否是SingleThreadEventExecutor
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 && wakesUpForTask(task)) {
//唤醒阻塞的selector
wakeup(inEventLoop);
}
}
}
由于刚才已经启动线程了,也将线程的信息存到thread
中去了,所以这儿调用NinEventLoop();
方法就会返回的是true,所以下面的if
判断就会为false
这样就不会启动线程了,而是将这个任务添加到taskQueue
这个任务队列中去,等待下一次轮训的时候调用到它,我们继续查看register0()
方法,让我们继续重现原来的代码,具体的代码如下:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
// 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
// 调用在eventLoop之外
//promise=DefaultChannelPromise
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
//调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法 选择器看不同操作系统
doRegister();
neverRegistered = false;
registered = true;
// 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
// 用户可能已经通过ChannelFutureListener中的管道触发事件。
// 会执行handlerAdded方法
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//会执行channelRegistered
pipeline.fireChannelRegistered();
// 只有当通道从未被注册时,才激活该通道。这可以防止解雇
// 如果取消注册并重新注册通道,则多个通道将激活。
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
// 这样我们就可以处理入站数据。
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// 直接关闭通道,避免FD泄漏。
closeForcibly();
loseFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
}
这个时候pipeline.invokeHandlerAddedIfNeeded();
已经执行完成,要执行下面的safeSetSuccess(promise);
方法了,我们继续跟进相应的代码,具体的代码如下:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected final void safeSetSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
}
上面的代码由于传进来的promise
是DefaultChannelPromise
,而VoidChannelPromise
没有子类,所以这个前面的判断就为true
,这个时候就会执行promise.trySuccess()
方法,我们继续跟进去看看,具体的代码如下:
public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
@Override
public boolean trySuccess() {
return trySuccess(null);
}
}
上面的代码继续调用trySuccess(null);
,我们继续跟进去看看对应的代码,具体的代码如下:
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
@Override
public boolean trySuccess(V result) {
return setSuccess0(result);
}
private boolean setSuccess0(V result) {
return setValue0(result == null ? SUCCESS : result);
}
private boolean setValue0(Object objResult) {
//记住这儿的CAS设置值,这儿设置完就表示注册完成了,后面调用dobind0方法会用到
if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
//由于前面添加了一个监听器,所以这儿的判断是不会为false的
if (checkNotifyWaiters()) {
notifyListeners();
}
return true;
}
return false;
}
private void notifyListeners() {
//这儿获取的NioEventLoop
EventExecutor executor = executor();
//这个判断是成立的,还是当前线程执行这个任务
if (executor.inEventLoop()) {
final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
//获取futureListener的栈的深度,这儿获取的是0
final int stackDepth = threadLocals.futureListenerStackDepth();
//当栈的深度小于8的时候
if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
//将futureListener的栈的深度加上1
threadLocals.setFutureListenerStackDepth(stackDepth + 1);
try {
//调用如下的方法
notifyListenersNow();
} finally {
threadLocals.setFutureListenerStackDepth(stackDepth);
}
return;
}
}
safeExecute(executor, new Runnable() {
@Override
public void run() {
notifyListenersNow();
}
});
}
private void notifyListenersNow() {
Object listeners;
synchronized (this) {
// 仅在有要通知的侦听器且我们尚未通知侦听器时继续进行
// 下面两个值notifyingListeners初始为false
// 这儿这个listeners不为空,我们在之前添加了一个监听器
if (notifyingListeners || this.listeners == null) {
return;
}
notifyingListeners = true;
listeners = this.listeners;
this.listeners = null;
}
//由于前面添加ChannelFutureListener类,所以下面的判断是会执行else中代码
for (;;) {
if (listeners instanceof DefaultFutureListeners) {
notifyListeners0((DefaultFutureListeners) listeners);
} else {
notifyListener0(this, (GenericFutureListener<?>) listeners);
}
synchronized (this) {
if (this.listeners == null) {
// Nothing can throw from within this method, so setting notifyingListeners back to false does not
// need to be in a finally block.
notifyingListeners = false;
return;
}
listeners = this.listeners;
this.listeners = null;
}
}
}
//执行下面的的方法
private static void notifyListener0(Future future, GenericFutureListener l) {
try {
//这个时候会调用到我们原来在AbstractBootstrap的dobind方法中添加的监听器
l.operationComplete(future);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
}
}
}
}
上面代码最终会调用我在AbstractBootstrap
的dobind
方法中添加的监听器,这个时候调用的代码就如下所示:
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化和注册
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();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
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;
}
}
}
上面的监听器会调用operationComplete(ChannelFuture future)
方法,由于前面没有异常,所以这儿会调用doBind0(regFuture, channel, localAddress, promise);
方法,我们继续跟进去查看对应的代码,具体的代码如下:
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// 在触发channelregister()之前调用此方法。给用户处理程序设置的机会
// 管道在其channelRegistered()实现中。
//这些任务最终被事件轮询线程同步调用
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
System.out.println(" channel.eventLoop().execute(new Runnable() ");
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
}
你会发现上面的代码一样是往taskQueue
中添加了一个任务,等待对应的线程调用。到这里register0()
方法中的safeSetSuccess(promise);
就执行完成了。要记住这儿taskQueue
中有两个任务,一个是添加ServerBootstrapAcceptor
类到pipeline
,还有一个就是执行dobind0()
方法。我们再次回到执行原来的代码的地方,具体的代码如下:
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
// 检查通道是否仍然打开,因为它可以在寄存器的平均时间内关闭
// 调用在eventLoop之外
//promise=DefaultChannelPromise
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
//调用NioServerSocketChannel 通过反射创建出来nio底层channel的register方法 选择器看不同操作系统
doRegister();
neverRegistered = false;
registered = true;
// 确保在实际通知承诺之前调用handlerAdded(…)。这是需要的
// 用户可能已经通过ChannelFutureListener中的管道触发事件。
// 会执行handlerAdded方法
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//会执行channelRegistered
pipeline.fireChannelRegistered();
// 只有当通道从未被注册时,才激活该通道。这可以防止解雇
// 如果取消注册并重新注册通道,则多个通道将激活。
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// 这个通道之前已经注册,并设置了autoRead()。这意味着我们需要开始读取
// 这样我们就可以处理入站数据。
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// 直接关闭通道,避免FD泄漏。
closeForcibly();
loseFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
}
这个时候会调用对应的pipeline
的fireChannelRegistered();
方法,到此通道已经激活。所以下面的两个判断都不会进。这个这个任务就执行完成。所以下面会执行pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
往pipeline
中又添加了一个pipeline
,这个是pipeline
如下图所示:
下篇博客我会主要介绍另一个任务dobind0()
方法,同样也是一个核心的方法。