Netty版本4.0.29.Final,以構(gòu)造客戶端連接服務(wù)端的角度來追蹤源碼
一 創(chuàng)建Netty事件循環(huán)組
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
NioEventLoopGroup的構(gòu)造器中會(huì)調(diào)用父類MultithreadEventLoopGroup的構(gòu)造器
- SelectorProvider.provider()返回運(yùn)行JVM的操作系統(tǒng)提供的provider
- 如果沒有指定線程數(shù)量,默認(rèn)為兩倍核數(shù)
// NioEventLoopGroup
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, null);
}
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
this(nThreads, threadFactory, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {
super(nThreads, threadFactory, selectorProvider);
}
// MultithreadEventLoopGroup
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
}
在父類MultithreadEventExecutorGroup的構(gòu)造器中
- 創(chuàng)建默認(rèn)的線程工廠,后續(xù)用來創(chuàng)建線程
- 創(chuàng)建一個(gè)SingleThreadEventExecutor數(shù)組,數(shù)組大小為兩倍核數(shù),保存在屬性children上
- 創(chuàng)建選擇器保存在屬性chooser上
- 在newChild方法中創(chuàng)建EventExecutor填充到數(shù)組上
- newChild是父類MultithreadEventExecutorGroup提供的一個(gè)抽象方法,由于當(dāng)前是在創(chuàng)建NioEventLoopGroup對(duì)象,具體實(shí)現(xiàn)還是由NioEventLoopGroup完成。
- 可以看到NioEventLoopGroup中完成了NioEventLoop的創(chuàng)建
// MultithreadEventExecutorGroup
protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (threadFactory == null) {
threadFactory = newDefaultThreadFactory();
}
children = new SingleThreadEventExecutor[nThreads];
if (isPowerOfTwo(children.length)) {
chooser = new PowerOfTwoEventExecutorChooser();
} else {
chooser = new GenericEventExecutorChooser();
}
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(threadFactory, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
}
// NioEventLoopGroup
@Override
protected EventExecutor newChild(
ThreadFactory threadFactory, Object... args) throws Exception {
return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);
}
二 創(chuàng)建Netty事件循環(huán)
- 將一開始創(chuàng)建的provider保存在屬性provider上
- openSelector中返回操作系統(tǒng)提供的selector(多路復(fù)用器)
- 如果未禁用優(yōu)化(默認(rèn)未禁用),使用反射將操作系統(tǒng)返回的selector中的屬性selectedKeys和publicSelectedKeys改為可寫,并用Netty的SelectedSelectionKeySet代替
- 最后再看父類SingleThreadEventExecutor構(gòu)造器
// NioEventLoop
NioEventLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {
super(parent, threadFactory, false);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
provider = selectorProvider;
selector = openSelector();
}
private Selector openSelector() {
final Selector selector;
try {
selector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
if (DISABLE_KEYSET_OPTIMIZATION) {
return selector;
}
try {
SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Class<?> selectorImplClass =
Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
// Ensure the current selector implementation is what we can instrument.
if (!selectorImplClass.isAssignableFrom(selector.getClass())) {
return selector;
}
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
selectedKeysField.setAccessible(true);
publicSelectedKeysField.setAccessible(true);
selectedKeysField.set(selector, selectedKeySet);
publicSelectedKeysField.set(selector, selectedKeySet);
selectedKeys = selectedKeySet;
logger.trace("Instrumented an optimized java.util.Set into: {}", selector);
} catch (Throwable t) {
selectedKeys = null;
logger.trace("Failed to instrument an optimized java.util.Set into: {}", selector, t);
}
return selector;
}
- 事件循環(huán)組保存在屬性parent上。對(duì)于客戶端來說,這里的parent還是開始創(chuàng)建的NioEventLoopGroup(服務(wù)端可以有兩個(gè)具有父子關(guān)系的事件循環(huán)組)
- 使用線程工廠創(chuàng)建線程,封裝了匿名任務(wù)(后續(xù)會(huì)分析該任務(wù)),保存在屬性thread上(未啟動(dòng))
- 使用NioEventLoop的newTaskQueue創(chuàng)建一個(gè)無鎖并發(fā)的單消費(fèi)者多生產(chǎn)者隊(duì)列,保存在屬性taskQueue上
// SingleThreadEventExecutor
protected SingleThreadEventExecutor(
EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
}
this.parent = parent;
this.addTaskWakesUp = addTaskWakesUp;
thread = threadFactory.newThread(new Runnable() {
@Override
public void run() {
// 暫時(shí)不關(guān)注任務(wù)內(nèi)邏輯 省略
}
});
taskQueue = newTaskQueue();
}
// NioEventLoop
@Override
protected Queue<Runnable> newTaskQueue() {
// This event loop never calls takeTask()
return PlatformDependent.newMpscQueue();
}
// PlatformDependent
public static <T> Queue<T> newMpscQueue() {
return new MpscLinkedQueue<T>();
}
上面已經(jīng)完成了NioEventLoop的創(chuàng)建,并保存在NioEventLoopGroup的數(shù)組屬性上。而關(guān)于NioEventLoop在具備線程池能力時(shí),在何時(shí)啟動(dòng)已經(jīng)創(chuàng)建的線程呢?在SingleThreadEventExecutor::execute中可以找到答案
- 當(dāng)任務(wù)被提交到NioEventLoop以后,首先判斷提交任務(wù)的線程與thread屬性保存的線程是否是同一個(gè)
- 如果不是同一個(gè),startThread中根據(jù)維護(hù)的STATE_UPDATER來判斷當(dāng)前NioEventLoop是否已經(jīng)啟動(dòng)過,如果沒有,使用CAS更新該NioEventLoop狀態(tài)為已經(jīng)啟動(dòng)
- 然后啟動(dòng)該線程,后續(xù)如果再執(zhí)行該方法,由于線程已經(jīng)啟動(dòng),方法內(nèi)什么都不會(huì)做
- 再回到execute中,addTask將任務(wù)生產(chǎn)到之前創(chuàng)建的隊(duì)列中
// SingleThreadEventExecutor
@Override
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
if (inEventLoop) {
addTask(task);
} else {
startThread();
addTask(task);
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
// AbstractEventExecutor
@Override
public boolean inEventLoop() {
return inEventLoop(Thread.currentThread());
}
// SingleThreadEventExecutor
@Override
public boolean inEventLoop(Thread thread) {
return thread == this.thread;
}
// SingleThreadEventExecutor
private void startThread() {
if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
schedule(new ScheduledFutureTask<Void>(
this, Executors.<Void>callable(new PurgeTask(), null),
ScheduledFutureTask.deadlineNanos(SCHEDULE_PURGE_INTERVAL), -SCHEDULE_PURGE_INTERVAL));
thread.start();
}
}
}
// SingleThreadEventExecutor
protected void addTask(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
if (isShutdown()) {
reject();
}
taskQueue.add(task);
}
而關(guān)于NioEventLoop內(nèi)線程啟動(dòng)后的邏輯,可以在創(chuàng)建該線程時(shí)看到有向線程提交一個(gè)任務(wù)。根據(jù)任務(wù)內(nèi)SingleThreadEventExecutor.this.run()可以定位到創(chuàng)建線程提交任務(wù)的NioEventLoop::run
// SingleThreadEventExecutor
thread = threadFactory.newThread(new Runnable() {
@Override
public void run() {
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_UPDATER.get(SingleThreadEventExecutor.this);
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) {
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()) {
logger.warn(
"An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
terminationFuture.setSuccess(null);
}
}
}
}
});
NioEventLoop::run是Netty的核心所在。它是NioEventLoop的線程執(zhí)行的唯一任務(wù)。方法內(nèi)無限循環(huán),阻塞等待IO事件或隊(duì)列中的任務(wù)
- 判斷NioEventLoop的隊(duì)列中是否有任務(wù)
- 如果有,執(zhí)行一次selectNow,這會(huì)導(dǎo)致多路復(fù)用器上準(zhǔn)備就緒的事件被分配到selectedKeys上(jdk nio基礎(chǔ),操作系統(tǒng)介入)
- 如果沒有,執(zhí)行select(oldWakenUp);,阻塞oldWakenUp時(shí)間后,開始下一個(gè)循環(huán)(阻塞期間等待多路復(fù)用器上準(zhǔn)備就緒的事件被分配到selectedKeys上)
- 根據(jù)設(shè)置的IO事件的執(zhí)行比例(默認(rèn)50%),計(jì)算出執(zhí)行隊(duì)列任務(wù)的最長執(zhí)行時(shí)間(先記錄IO事件執(zhí)行的總耗時(shí),然后根據(jù)比例,計(jì)算出執(zhí)行隊(duì)列任務(wù)的最長執(zhí)行時(shí)間)
// NioEventLoop
@Override
protected void run() {
for (;;) {
boolean oldWakenUp = wakenUp.getAndSet(false);
try {
if (hasTasks()) {
selectNow();
} else {
select(oldWakenUp);
if (wakenUp.get()) {
selector.wakeup();
}
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
processSelectedKeys();
runAllTasks();
} else {
final long ioStartTime = System.nanoTime();
processSelectedKeys();
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
break;
}
}
} catch (Throwable t) {
logger.warn("Unexpected exception in the selector loop.", t);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
執(zhí)行IO事件
- 在有IO事件就緒時(shí),處理for循環(huán)本次循環(huán)取出的這些事件
- 這里有看到unsafe類的介入,對(duì)于客戶端而言,可能存在的IO事件有建立連接的應(yīng)答,或者服務(wù)端主動(dòng)發(fā)送消息給客戶端
- 交由unsafe來處理的對(duì)應(yīng)方法分別為unsafe::finishConnect和unsafe::read
- 對(duì)unsafe的分析將在后面完成,這里暫時(shí)不展開
// NioEventLoop
private void processSelectedKeys() {
if (selectedKeys != null) {
processSelectedKeysOptimized(selectedKeys.flip());
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
}
private void processSelectedKeysOptimized(SelectionKey[] selectedKeys) {
for (int i = 0;; i ++) {
final SelectionKey k = selectedKeys[i];
if (k == null) {
break;
}
// null out entry in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
selectedKeys[i] = null;
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (needsToSelectAgain) {
// null out entries in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
for (;;) {
if (selectedKeys[i] == null) {
break;
}
selectedKeys[i] = null;
i++;
}
selectAgain();
// Need to flip the optimized selectedKeys to get the right reference to the array
// and reset the index to -1 which will then set to 0 on the for loop
// to start over again.
//
// See https://github.com/netty/netty/issues/1523
selectedKeys = this.selectedKeys.flip();
i = -1;
}
}
}
private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
}
try {
int readyOps = k.readyOps();
// 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) {
unsafe.read();
if (!ch.isOpen()) {
// Connection already closed - no need to handle write.
return;
}
}
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
ch.unsafe().forceFlush();
}
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// 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();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
執(zhí)行隊(duì)列任務(wù)
關(guān)于隊(duì)列中的任務(wù)從哪里來?一是源碼內(nèi)部,啟動(dòng)時(shí)會(huì)直接提交任務(wù)到隊(duì)列中;二是可以直接取出channel中的NioEventLoop向其提交任務(wù);三是使用Channel寫數(shù)據(jù)時(shí),都是以任務(wù)的形式提交到隊(duì)列中。與Channel綁定的NioEventLoop循環(huán)時(shí)會(huì)消費(fèi)提交到隊(duì)列中任務(wù)并執(zhí)行,后續(xù)在分析unsafe時(shí)會(huì)一并提及。
- IO事件執(zhí)行完成后,回到NioEventLoop::run中,在runAllTasks中開始執(zhí)行隊(duì)列中的任務(wù)
- pollTask從隊(duì)列中取出一個(gè)任務(wù),接著在for循環(huán)中執(zhí)行該任務(wù),并重復(fù)取出任務(wù)、執(zhí)行任務(wù)的過程
- 退出for循環(huán)的條件有兩個(gè),一是隊(duì)列中沒有需要執(zhí)行的任務(wù),二是到了執(zhí)行定時(shí)任務(wù)的時(shí)間
// NioEventLoop
protected boolean runAllTasks(long timeoutNanos) {
fetchFromScheduledTaskQueue();
Runnable task = pollTask();
if (task == null) {
return false;
}
final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
long runTasks = 0;
long lastExecutionTime;
for (;;) {
try {
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception.", t);
}
runTasks ++;
// Check timeout every 64 tasks because nanoTime() is relatively expensive.
// XXX: Hard-coded value - will make it configurable if it is really a problem.
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
task = pollTask();
if (task == null) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
break;
}
}
this.lastExecutionTime = lastExecutionTime;
return true;
}
三 客戶端Channel類型
客戶端Bootstrap配置引導(dǎo)時(shí),需要指定Channel類型,后續(xù)會(huì)使用反射創(chuàng)建該Channel類型實(shí)例。
- 假設(shè)以Channel類型為NioSocketChannel來跟蹤源碼
- 一系列構(gòu)造器之間的調(diào)用,將JDK原生的SocketChannel作為屬性保存在父類AbstractChannel的parent屬性上
- 創(chuàng)建NioSocketChannelUnsafe實(shí)例保存在父類AbstractChannel屬性u(píng)nsafe上
- 創(chuàng)建管道DefaultChannelPipeline保存在父類AbstractChannel屬性pipeline上
- 管道DefaultChannelPipeline中默認(rèn)擁有head和tail兩個(gè)ChannelHandler,構(gòu)成只有頭尾兩節(jié)點(diǎn)的雙向鏈表。
// NioSocketChannel
public NioSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
public NioSocketChannel(SocketChannel socket) {
this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
config = new NioSocketChannelConfig(this, socket.socket());
}
// AbstractNioByteChannel
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
super(parent, ch, SelectionKey.OP_READ);
}
// AbstractNioChannel
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false);
} catch (IOException e) {
try {
ch.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
}
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
// AbstractChannel
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe();
pipeline = new DefaultChannelPipeline(this);
}
// NioSocketChannel
@Override
protected AbstractNioUnsafe newUnsafe() {
return new NioSocketChannelUnsafe();
}
// DefaultChannelPipeline
public DefaultChannelPipeline(AbstractChannel channel) {
if (channel == null) {
throw new NullPointerException("channel");
}
this.channel = channel;
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
四 客戶端建立連接
bootstrap.connect()
客戶端完成NioEventLoopGroup和Bootstrap的創(chuàng)建及對(duì)Bootstrap進(jìn)行相關(guān)的設(shè)置后,使用Bootstrap嘗試與服務(wù)端建立連接。在同步與異步之間,推薦使用異步來監(jiān)聽連接事件的結(jié)果。
- 一些必須的參數(shù)校驗(yàn)
- 由于是與服務(wù)器建立連接,localAddress值為null
- doConnect中先調(diào)用initAndRegister異步創(chuàng)建通道及注冊(cè)
- 無論是使用isDone還是使用監(jiān)聽器,都是在通道創(chuàng)建完成后,使用doConnect0進(jìn)行連接
// Bootstrap
public ChannelFuture connect() {
validate();
SocketAddress remoteAddress = this.remoteAddress;
if (remoteAddress == null) {
throw new IllegalStateException("remoteAddress not set");
}
return doConnect(remoteAddress, localAddress());
}
private ChannelFuture doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
final ChannelPromise promise = channel.newPromise();
if (regFuture.isDone()) {
doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
} else {
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
doConnect0(regFuture, channel, remoteAddress, localAddress, promise);
}
});
}
return promise;
}
AbstractBootstrap是Bootstrap的父類,initAndRegister中完成了通道的創(chuàng)建、初始化以及注冊(cè)
- 使用Bootstrap中默認(rèn)的BootstrapChannelFactory,根據(jù)設(shè)置的channel,使用反射創(chuàng)建channel實(shí)例
- 假設(shè)使用上述NioSocketChannel,當(dāng)然也可以是別的channel類型
- init負(fù)責(zé)對(duì)創(chuàng)建的channel初始化
- 初始化完成后異步完成注冊(cè)
// AbstractBootstrap
final ChannelFuture initAndRegister() {
final Channel channel = channelFactory().newChannel();
try {
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);
}
ChannelFuture regFuture = 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;
}
Channel初始化
- init方法還是交由子類Bootstrap實(shí)現(xiàn)
- 取出channel上的管道,將客戶端自定義的handler添加進(jìn)去,底層其實(shí)是對(duì)雙向鏈表的變更,如DefaultChannelPipeline::addLast0所示,這時(shí)會(huì)形成head、自定義ChannelInitializer、tail三個(gè)節(jié)點(diǎn)
- 對(duì)channel的option和attr進(jìn)行設(shè)置,以支持將自定義參數(shù)配置到channel上
// Bootstrap
@Override
@SuppressWarnings("unchecked")
void init(Channel channel) throws Exception {
ChannelPipeline p = channel.pipeline();
p.addLast(handler());
final Map<ChannelOption<?>, Object> options = options();
synchronized (options) {
for (Entry<ChannelOption<?>, Object> e: options.entrySet()) {
try {
if (!channel.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {
logger.warn("Unknown channel option: " + e);
}
} catch (Throwable t) {
logger.warn("Failed to set a channel option: " + channel, t);
}
}
}
final Map<AttributeKey<?>, Object> attrs = attrs();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
}
}
// DefaultChannelPipeline
private void addLast0(final String name, AbstractChannelHandlerContext newCtx) {
checkMultiplicity(newCtx);
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
name2ctx.put(name, newCtx);
callHandlerAdded(newCtx);
}
Channel注冊(cè)
group()取到開始配置的NioEventLoopGroup,register在父類MultithreadEventLoopGroup中
- next()內(nèi)借助之前生成的chooser的next()方法,選出MultithreadEventExecutorGroup中child數(shù)組上的一個(gè)NioEventLoop
- 接著變成NioEventLoop::register方法,該方法來自父類SingleThreadEventLoop
- 在SingleThreadEventLoop中再轉(zhuǎn)換為channel上unsafe::register,關(guān)于unsafe暫時(shí)先不展開介紹。
// MultithreadEventLoopGroup
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
// MultithreadEventExecutorGroup
@Override
public EventExecutor next() {
return chooser.next();
}
// GenericEventExecutorChooser
private final class GenericEventExecutorChooser implements EventExecutorChooser {
@Override
public EventExecutor next() {
return children[Math.abs(childIndex.getAndIncrement() % children.length)];
}
}
// SingleThreadEventLoop
@Override
public ChannelFuture register(Channel channel) {
return register(channel, new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
if (channel == null) {
throw new NullPointerException("channel");
}
if (promise == null) {
throw new NullPointerException("promise");
}
channel.unsafe().register(this, promise);
return promise;
}
Channel管道初始化
雖說暫時(shí)不引入unsafe類邏輯,但在unsafe::register中,通道注冊(cè)完成后會(huì)調(diào)用管道的fireChannelRegistered方法,進(jìn)而執(zhí)行自定義的ChannelInitializer,最終形成完整的管道。
目前管道上鏈表有三個(gè)節(jié)點(diǎn):head、自定義ChannelInitializer、tail(規(guī)定自頭向尾的流向?yàn)镮n,自尾向頭的為Out)
它們的類型都是AbstractChannelHandlerContext,每個(gè)Context上都持有對(duì)應(yīng)的ChannelHandler
- 首先head執(zhí)行父類方法fireChannelRegistered,該方法找到以In流向的下一個(gè)AbstractChannelHandlerContext
- 然后在invokeChannelRegistered中找到Context持有的Handler,執(zhí)行Handler::channelRegistered
- 自定義的ChannelInitializer屬于ChannelInboundHandler的子類,流向?yàn)镮n。其channelRegistered方法執(zhí)行時(shí),調(diào)用被重寫的initChannel方法
- initChannel方法內(nèi)一般定義的是業(yè)務(wù)自身往管道添加Handler的邏輯ChannelPipeline::addLast
- addLast之前自定義ChannelInitializer已經(jīng)有分析過,目的是將ChannelHandler封裝為Context添加到管道上,并根據(jù)實(shí)現(xiàn)的接口標(biāo)記節(jié)點(diǎn)流向,最終形成完整的雙向鏈表
- 最后回到ChannelInitializer::channelRegistered中,將自定義的ChannelInitializer移出,因?yàn)樗恍枰赾hannel初始化時(shí)發(fā)揮作用,不需要存在于實(shí)際的管道中
// DefaultChannelPipeline
@Override
public ChannelPipeline fireChannelRegistered() {
head.fireChannelRegistered();
return this;
}
// AbstractChannelHandlerContext
@Override
public ChannelHandlerContext fireChannelRegistered() {
final AbstractChannelHandlerContext next = findContextInbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new OneTimeTask() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
return this;
}
private void invokeChannelRegistered() {
try {
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
// ChannelInitializer
@Override
@SuppressWarnings("unchecked")
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ChannelPipeline pipeline = ctx.pipeline();
boolean success = false;
try {
initChannel((C) ctx.channel());
pipeline.remove(this);
ctx.fireChannelRegistered();
success = true;
} catch (Throwable t) {
logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);
} finally {
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
if (!success) {
ctx.close();
}
}
}
Channel連接
至此,Channel的初始化及注冊(cè)已經(jīng)完成。回到Bootstrap::doConnect中,在Channel注冊(cè)這個(gè)異步任務(wù)完成后,開始真正的連接服務(wù)端
- 獲取到Channel綁定的NioEventLoop,提交任務(wù)到線程池
- 任務(wù)被觸發(fā)時(shí),使用channel進(jìn)行連接
- 使用channel上的管道pipeline進(jìn)行連接,從tailf開始,以O(shè)ut的流向,找到下一個(gè)Out節(jié)點(diǎn),執(zhí)行其invokeConnect
- 最終流到head節(jié)點(diǎn),head內(nèi)繼續(xù)使用unsafe與服務(wù)端進(jìn)行連接的建立
// Bootstrap類
private static void doConnect0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress remoteAddress, 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() {
if (regFuture.isSuccess()) {
if (localAddress == null) {
channel.connect(remoteAddress, promise);
} else {
channel.connect(remoteAddress, localAddress, promise);
}
promise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
// AbstractChannel
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return pipeline.connect(remoteAddress, promise);
}
// DefaultChannelPipeline
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return tail.connect(remoteAddress, promise);
}
// AbstractChannelHandlerContext
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return connect(remoteAddress, null, promise);
}
@Override
public ChannelFuture connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
if (remoteAddress == null) {
throw new NullPointerException("remoteAddress");
}
if (!validatePromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeConnect(remoteAddress, localAddress, promise);
} else {
safeExecute(executor, new OneTimeTask() {
@Override
public void run() {
next.invokeConnect(remoteAddress, localAddress, promise);
}
}, promise, null);
}
return promise;
}
private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
try {
((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}
// HeadContext
@Override
public void connect(
ChannelHandlerContext ctx,
SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) throws Exception {
unsafe.connect(remoteAddress, localAddress, promise);
}
五 客戶端發(fā)送數(shù)據(jù)
channel.write("test");
channel連接建立完成后,可以使用channel寫數(shù)據(jù)
- 使用channel寫數(shù)據(jù)時(shí),從channel開始,經(jīng)過管道,找到tail開始執(zhí)行寫數(shù)據(jù)邏輯
- tail作為雙向鏈表的尾部,使用自尾向頭的Out流向,找到下一個(gè)Context,直到最終流到head節(jié)點(diǎn)
- head節(jié)點(diǎn)轉(zhuǎn)化為unsafe::write,在后面分析
// AbstractChannel
@Override
public ChannelFuture write(Object msg) {
return pipeline.write(msg);
}
// DefaultChannelPipeline
@Override
public ChannelFuture write(Object msg) {
return tail.write(msg);
}
// AbstractChannelHandlerContext
@Override
public ChannelFuture write(Object msg) {
return write(msg, newPromise());
}
@Override
public ChannelFuture write(final Object msg, final ChannelPromise promise) {
if (msg == null) {
throw new NullPointerException("msg");
}
if (!validatePromise(promise, true)) {
ReferenceCountUtil.release(msg);
// cancelled
return promise;
}
write(msg, false, promise);
return promise;
}
private void write(Object msg, boolean flush, ChannelPromise promise) {
AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeWrite(msg, promise);
if (flush) {
next.invokeFlush();
}
} else {
int size = channel.estimatorHandle().size(msg);
if (size > 0) {
ChannelOutboundBuffer buffer = channel.unsafe().outboundBuffer();
// Check for null as it may be set to null if the channel is closed already
if (buffer != null) {
buffer.incrementPendingOutboundBytes(size);
}
}
Runnable task;
if (flush) {
task = WriteAndFlushTask.newInstance(next, msg, size, promise);
} else {
task = WriteTask.newInstance(next, msg, size, promise);
}
safeExecute(executor, task, promise, msg);
}
}
private void invokeWrite(Object msg, ChannelPromise promise) {
try {
((ChannelOutboundHandler) handler()).write(this, msg, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}
// HeadContext
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
unsafe.write(msg, promise);
}
寫數(shù)據(jù)不會(huì)直接發(fā)送數(shù)據(jù)到服務(wù)端,而是會(huì)緩存起來,直到調(diào)用flush才會(huì)完成數(shù)據(jù)的最終發(fā)送。flush邏輯與寫數(shù)據(jù)一樣,channel到pipeline,tail到head。最終交由unsafe類來完成
channel.flush();
@Override
public void flush(ChannelHandlerContext ctx) throws Exception {
unsafe.flush();
}
六 總結(jié)
以客戶端建立連接發(fā)送數(shù)據(jù)流程為例(服務(wù)端大部分邏輯相似),總結(jié)Netty的工作流程:
- 聲明NioEventLoopGroup(事件循環(huán)組),內(nèi)部會(huì)創(chuàng)建兩倍核數(shù)大小的數(shù)組,并為數(shù)組上的每一個(gè)位置分配NioEventLoop(事件循環(huán)),NioEventLoop內(nèi)包含一個(gè)未啟動(dòng)線程和一個(gè)任務(wù)隊(duì)列
- 聲明Bootstrap(引導(dǎo)),指定事件循環(huán)組、遠(yuǎn)程地址、option、attr、channel類型和自定義的ChannelInitializer
- 使用Bootstrap發(fā)起建立連接請(qǐng)求
- 使用反射根據(jù)指定的channel類型創(chuàng)建channel實(shí)例
- 對(duì)channel實(shí)例進(jìn)行初始化,配置自定義ChannelInitializer到channel管道中,設(shè)置option和attr
- 從NioEventLoopGroup維護(hù)的數(shù)組中選出NioEventLoop,借助NioEventLoop開始channel的注冊(cè)邏輯
- 這個(gè)過程會(huì)激活NioEventLoop內(nèi)創(chuàng)建的線程。該線程進(jìn)而啟動(dòng)一個(gè)無限for循環(huán),開始接收多路復(fù)用器上就緒的IO事件,同時(shí)執(zhí)行NioEventLoop內(nèi)隊(duì)列上的任務(wù)
- 接著channel會(huì)與該NioEventLoop綁定,并將channel注冊(cè)到多路復(fù)用器上
- channel注冊(cè)完成后,執(zhí)行為channel指定的ChannelInitializer,最終在channel上形成完整的管道配置
- 再設(shè)置channel為readPending的狀態(tài)
- 待channel準(zhǔn)備就緒后,使用channel建立與服務(wù)端的連接,發(fā)起建立連接的請(qǐng)求,由NioEventLoop完成
- 處理服務(wù)端返回的建立請(qǐng)求應(yīng)答,IO事件由NioEventLoop完成
- Bootstrap在連接建立完成后返回channel實(shí)例,使用channel實(shí)例完成數(shù)據(jù)的發(fā)送。同時(shí)與channel綁定的NioEventLoop內(nèi)的線程,監(jiān)聽并處理多路復(fù)用器上準(zhǔn)備就緒的IO事件(接收服務(wù)端數(shù)據(jù)應(yīng)答或服務(wù)端主動(dòng)發(fā)起的數(shù)據(jù))