Netty源码阅读(二)-Netty启动流程源码

一、Netty启动流程源码

上一篇文章中的Netty服务端启动代码中,bind()方法才是Netty真正开始启动的地方。跟踪代码,会进入AbstractBootstrap#doBind()方法

private ChannelFuture doBind(final SocketAddress localAddress) {
	//初始化并注册一个channel
	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();
		//执行channel.bind()
		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.executor = channel.eventLoop();
				}
				doBind0(regFuture, channel, localAddress, promise);
			}
		});
		return promise;
	}
}
1、NioServerSocketChannel的初始化:

AbstractBootstrap#initAndRegister

final ChannelFuture initAndRegister() {
	// 还记得前面我们设置过channel工厂么,终于派上用场了
	final Channel channel = channelFactory().newChannel();
	try {
		//初始化channel(就是NioServerSocketChannel)
		init(channel);
	} catch (Throwable t) {
		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);
	}
	
	// 向EventLoopGroup - BossGroup中注册一个channel
	ChannelFuture regFuture = group().register(channel);
	if (regFuture.cause() != null) {
		if (channel.isRegistered()) {
			channel.close();
		} else {
			channel.unsafe().closeForcibly();
		}
	}
	return regFuture;
}

ServerBootstrap#init:

void init(Channel channel) throws Exception {

*******

	// 获取channel绑定的pipeline(pipeline实在channel创建的时候创建并绑定的)
	ChannelPipeline p = channel.pipeline();
	// 如果用户配置过Handler,为NioServerSocketChannel绑定的pipeline添加Handler
	if (handler() != null) {
		p.addLast(handler());
	}
	
	//开始准备WorkerGroup用到的4个part,因为接下来就要使用它们。
	final EventLoopGroup currentChildGroup = childGroup;
	final ChannelHandler currentChildHandler = childHandler;
	final Entry<ChannelOption<?>, Object>[] currentChildOptions;
	final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
	synchronized (childOptions) {
		currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
	}
	synchronized (childAttrs) {
		currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
	}
	
	// 为NioServerSocketChannel的pipeline添加一个初始化Handler,
	// 当NioServerSocketChannel在EventLoop注册成功时,该handler的init方法将被调用
	p.addLast(new ChannelInitializer<Channel>() {
		@Override
		public void initChannel(Channel ch) throws Exception {
		
			// 为NioServerSocketChannel的pipeline添加一个Handler:ServerBootstrapAcceptor处理器 
			// 该Handler主要用来监听channelRead事件,将新产生的channel绑定到WorkerGroup中的某个EventLoop
			ch.pipeline().addLast(new ServerBootstrapAcceptor(                     
					currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
		}
	});
}

由上段代码可知,正是在此处将BossGroup、WorkerGroup关联起来,BossGroup主要是监听Accept事件,WorkerGroup主要是监听Read/Write事件,分工明确!ServerBootstrapAcceptor 这个Handler的作用具体体现在Netty线程模型的红线标注的地方:
在这里插入图片描述
NioServerSocketChannel执行完init()方法之后,再来看下NioServerSocketChannel是如何注册到NioEventLoop中的Selector上的。

2、NioServerSocketChannel的注册
// 向EventLoopGroup - BossGroup中注册一个channel
ChannelFuture regFuture = group().register(channel);

先看下调用链:

MultithreadEventLoopGroup#register(io.netty.channel.Channel)
	-> SingleThreadEventLoop#register(io.netty.channel.Channel)
		-> SingleThreadEventLoop#register(io.netty.channel.ChannelPromise)
			-> AbstractChannel.AbstractUnsafe#register
				->AbstractChannel.AbstractUnsafe#register0

AbstractChannel.AbstractUnsafe#register0

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();
		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会触发init时添加的Handler-ChannelInitializer
		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);
	}
}

AbstractNioChannel#doRegister

protected void doRegister() throws Exception {
 boolean selected = false;
 for (;;) {
     try {
     	 // 完成在EventLoop的Selector上的注册
		 // 注意,此时op位为0,channel还不能监听读写事件
         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;
         }
     }
 }
}
3、NioEventLoop的调用

在服务端启动流程中当执行到注册操作时,会判断当前线程是否是ServerSocketChannel所绑定的NioEventLoop中的线程,如果不是的话,会将注册操作封装成一个线程任务交给NioEventLoop中的线程去执行,相关代码如下所示:
AbstractChannel.AbstractUnsafe#register:

@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {

******

    AbstractChannel.this.eventLoop = eventLoop;

	// 判断当前线程是否是ServerSocketChannel所绑定的线程EventLoop中的线程
    // 由于目前处于启动阶段,当前线程是main线程,所以inEventLoop应为false
    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
		
			// 调用eventLoop.execute(Runnable runnable)方法将任务提交给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);
        }
    }
}

相关逻辑在父类SingleThreadEventxecutor类中实现:

public void execute(Runnable task) {
    if (task == null) {//合法性校验
        throw new NullPointerException("task");
    }
	// 判断当前线程是否是ServerSocketChannel所绑定的线程EventLoop中的线程
    // 由于目前处于启动阶段,当前线程是main线程,所以inEventLoop应为false
    boolean inEventLoop = inEventLoop(); 
	//将线程任务添加到EventLoop中的任务队列
    addTask(task);
    if (!inEventLoop) {
		// 启动线程
        startThread();
        // 如果线程已经关闭则移除上面提交到任务队列中的任务,并调用拒绝策略,拒绝任务的执行
        if (isShutdown() && removeTask(task)) {
            reject();
        }
    }

    if (!addTaskWakesUp && wakesUpForTask(task)) {
        wakeup(inEventLoop);
    }
}

SingleThreadEventExecutor#doStartThread

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 {
			
				// 执行NioEventLoop的地方
				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 {
						STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
						threadLock.release();
						if (!taskQueue.isEmpty()) {
							if (logger.isWarnEnabled()) {
								logger.warn("An event executor terminated with " +
										"non-empty task queue (" + taskQueue.size() + ')');
							}
						}

						terminationFuture.setSuccess(null);
					}
				}
			}
		}
	});
}

上述代码中可以看到,SingleThreadEventExecutor来执行NioEventLoop的run()方法,具体run()方法的执行内容可以查看《Netty源码阅读(一)-核心组件》的第三节内容——NioEventLoop。

二、Netty启动流程总结

由上述的源码分析可知,Netty的启动流程,其实大体如下:

1、将NioServerSocketChannel初始化后,注册到BossGroup的NioEventLoop的Selector上,并且注册监听的是Accept事件。

2、BossGroup的NioEventLoop执行run()方法,循环执行Select()、processSelectedKeys()、runAllTasks()方法;
(此时NioServerSocketChannel的pipeline添加一个Handler:ServerBootstrapAcceptor处理器, 这个Handler将NioSocketChannel注册到WorkerGroup的NioEventLoop的Selector上,并且注册监听的是Read/Write事件。)

3、WorkerGroup的NioEventLoop执行run()方法,循环执行Select()、processSelectedKeys()、runAllTasks()方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值