1、Channel、ChannelPipeline、ChannelHandler、ChannelHandlerContext關系
四者關系如下圖:
Channel:Channel為通信載體,負責底層傳輸層的具體事件及消息處理,其封裝底層處理的復雜性,通過統一接口將事件及消息交給ChannelPipeline處理。
ChannelPipeline:ChannelPipeline為消息的管道,一個Channel對應唯一ChannelPipeline,ChannelPipeline中包含多個ChannelHandlerContext,各個ChannelHandlerContext以鏈表的形式構成消息處理的責任鏈,而ChannelPipeline并不對消息做處理,其只是轉發給ChannelHandlerContext處理,而ChannelHandlerContext又交給具體的ChannelHandler處理,并將處理后的消息沿著鏈表轉發給下一個ChannelHandlerContext。
ChannelHandlerContext:ChannelHandlerContext為ChannelPipeline和ChannelHandler的上下文,其保存對應的ChannelPipeline及ChannelHandler,并且根據添加順序,多個ChannelHandlerContext之間構成鏈表。ChannelHandlerContext提供和ChannelPipeline類似的方法,但調用ChannelHandlerContext上的方法只會從當前的ChannelHandler開始向下一個ChannelHandler傳播;而調用ChannelPipeline上的方法會從鏈表頭或尾向下傳播。
ChannelHandler:ChannelHandler為具體的消息處理類,其由應用層定義。消息由某個ChannelHandler處理完后,會沿著鏈表將消息交由下個ChannelHandler處理。
2、ChannelPipeline源碼分析
ChannelPipeline類繼圖:
說明:
Iterable:遍歷器接口,具體接口為:Iterable<Entry<String, ChannelHandler>>,其提供iterator()、forEach()等方法,用于遍歷管道中的ChannelHandler。
ChannelInboundInvoker:管道的入口事件處理接口,對于Channel中的入口事件都是通過此接口進行處理的。消息類型包括:register、unregister、active、inactive、exception、read等;
ChannelOutboundInvoker:管道的出口事件處理接口,對于Channel相關的出口事件都是通過此接口進行處理的。消息類型包括:bind、connect、close、write、flush等。
ChannelPipeline:管道相關操作接口,提供了對管道中的ChannelHandler進行增刪改查等接口,包括:addFirst、addLast等。
DefaultChannelPipeline:ChannelPipeline的默認實現類。
2.1、遍歷處理器
pipeline提供其對應的Handler的遍歷處理接口。Iterable<Entry<String, ChannelHandler>及ChannelPipeline中的部分方法。
2.1.1、方法說明
方法名稱 | 返回值 | 功能說明 |
---|---|---|
iterator() | Iterator<Map.Entry<String, ChannelHandler>> | 返回Map.Entry<String, ChannelHandler>的遍歷器,此map即為pipeline中所有Handler的name與Handler的map。 |
names() | List<String> | 返回所有handler的name的集合 |
toMap() | Map<String, ChannelHandler> | 返回handler的name與ChannelHandler的map |
2.1.2、方法實現
iterator()及toMap()方法實現:
public final Map<String, ChannelHandler> toMap() {
Map<String, ChannelHandler> map = new LinkedHashMap<String, ChannelHandler>();
AbstractChannelHandlerContext ctx = head.next;
for (;;) {
if (ctx == tail) {
return map;
}
map.put(ctx.name(), ctx.handler());
ctx = ctx.next;
}
}
@Override
public final Iterator<Map.Entry<String, ChannelHandler>> iterator() {
return toMap().entrySet().iterator();
}
由以上toMap()實現可知,map中為pipeline中從head到tail的handler的map;
2.2、inbound事件
當發生I/O事件時,如鏈路建立連接、鏈路關閉、讀取數據完成等,都會產生一個事件,事件在pipeline中進行傳播和處理,它是實際處理的總入口。netty將有限的網絡I/O事件進行統一抽象,ChannelInboundInvoker即為pipeline抽象的入口接口。pipeline中以fireXXX命名的方法都是從I/O線程流向用戶業務Handler的inbound消息。
2.2.1、方法說明
方法名稱 | 返回值 | 功能說明 |
---|---|---|
fireChannelRegistered() | ChannelInboundInvoker | 當Channel 已經注冊到它的EventLoop 并且能夠處理I/O 時被調用 |
fireChannelUnregistered() | ChannelInboundInvoker | 當Channel 從它的EventLoop 注銷并且無法處理任何I/O 時被調用 |
fireChannelActive() | ChannelInboundInvoker | 當Channel 處于活動狀態時被調用;Channel 已經連接/綁定并且已經就緒 |
fireChannelInactive() | ChannelInboundInvoker | 當Channel 離開活動狀態并且不再連接它的遠程節點時被調用 |
fireExceptionCaught(Throwable cause) | ChannelInboundInvoker | Channel異常事件 |
fireUserEventTriggered(Object event) | ChannelInboundInvoker | 當ChannelnboundHandler.fireUserEventTriggered()方法被調 |
fireChannelRead(Object msg) | ChannelInboundInvoker | 當從Channel 讀取數據時被調用 |
fireChannelReadComplete() | ChannelInboundInvoker | 當Channel上的一個讀操作完成時被調用 |
fireChannelWritabilityChanged() | ChannelInboundInvoker | 當Channel 的可寫狀態發生改變時被調用。用戶可以確保寫操作不會完成得太快(以避免發生OutOfMemoryError)或者可以在Channel 變為再次可寫時恢復寫入。可以通過調用Channel 的isWritable()方法來檢測Channel 的可寫性。與可寫性相關的閾值可以通過Channel.config().setWriteHighWatesetWriteHighWaterMark()和Channel.config().setWriteLowWaterMark()方法來設置 |
2.2.2、方法實現
pipeline中inbound事件的處理都非常簡單,其主要交由AbstractChannelHandlerContext中對應的靜態方法進行處理。
部分處理源碼如下:
@Override
public final ChannelPipeline fireChannelActive() {
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
@Override
public final ChannelPipeline fireChannelInactive() {
AbstractChannelHandlerContext.invokeChannelInactive(head);
return this;
}
@Override
public final ChannelPipeline fireExceptionCaught(Throwable cause) {
AbstractChannelHandlerContext.invokeExceptionCaught(head, cause);
return this;
}
@Override
public final ChannelPipeline fireUserEventTriggered(Object event) {
AbstractChannelHandlerContext.invokeUserEventTriggered(head, event);
return this;
}
@Override
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
@Override
public final ChannelPipeline fireChannelReadComplete() {
AbstractChannelHandlerContext.invokeChannelReadComplete(head);
return this;
}
@Override
public final ChannelPipeline fireChannelWritabilityChanged() {
AbstractChannelHandlerContext.invokeChannelWritabilityChanged(head);
return this;
}
2.3、outbound事件
ChannelOutboundInvoker是outbound消息的接口,由用戶或者代碼發起的I/O操作被稱為outbound消息,即為從pipeline中流程的消息的統稱。
2.3.1、方法說明
方法名稱 | 返回值 | 功能說明 |
---|---|---|
bind(SocketAddress localAddress) | ChannelFuture | 當請求將Channel 綁定到本地地址時被調用,綁定成功或失敗都通過ChannelFuture進行通知 |
connect(SocketAddress remoteAddress) | ChannelFuture | 當請求將Channel 連接到遠程節點時被調用,當連接超時時拋出ConnectTimeoutException,當連接被拒絕時,將拋出ConnectException |
connect(SocketAddress remoteAddress, SocketAddress localAddress) | ChannelFuture | |
disconnect() | ChannelFuture | 當請求將Channel 從遠程節點斷開時被調用,不論處理成功或失敗,都會進行通知 |
close() | ChannelFuture | 當請求關閉Channel 時被調用 |
deregister() | ChannelFuture | 當請求將Channel 從它的EventLoop 注銷時被調用 |
bind(SocketAddress localAddress, ChannelPromise promise) | ChannelFuture | 當請求將Channel 綁定到本地地址時被調用 |
connect(SocketAddress remoteAddress, ChannelPromise promise) | ChannelFuture | 當請求將Channel 連接到遠程節點時被調用 |
connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) | ChannelFuture | 當請求將Channel 連接到遠程節點時被調用 |
disconnect(ChannelPromise promise) | ChannelFuture | 當請求將Channel 從遠程節點斷開時被調用 |
close(ChannelPromise promise) | ChannelFuture | 請求關閉Channel 時被調用 |
deregister(ChannelPromise promise) | ChannelFuture | 當請求將Channel 從它的EventLoop 注銷時被調用 |
read() | ChannelFuture | 當請求從Channel 讀取更多的數據時被調用 |
write(Object msg) | ChannelFuture | 當請求通過Channel 將數據寫到遠程節點時被調用 |
write(Object msg, ChannelPromise promise) | ChannelFuture | 當請求通過Channel 將數據寫到遠程節點時被調用 |
flush() | ChannelOutboundInvoker | 當請求通過Channel 將入隊數據沖刷到遠程節點時被調用 |
writeAndFlush(Object msg, ChannelPromise promise) | ChannelFuture | 當請求通過Channel 將入隊數據沖刷到遠程節點時被調用 |
writeAndFlush(Object msg) | ChannelFuture | 當請求通過Channel 將入隊數據沖刷到遠程節點時被調用 |
newPromise() | ChannelPromise | 返回一個新的ChannelPromise |
newProgressivePromise() | ChannelProgressivePromise | 返回一個新的ChannelProgressivePromise |
newSucceededFuture() | ChannelFuture | 返回一個已被標記為成功的ChannelFuture,所有與此ChannelFuture綁定的監聽器都將被通知,所有阻塞調用也將直接返回 |
newFailedFuture(Throwable cause) | ChannelFuture | 返回一個已被標記為失敗的ChannelFuture,所有與此ChannelFuture綁定的監聽器都將被通知,所有阻塞調用也將直接返回 |
voidPromise() | ChannelPromise | 返回一個不同操作也重用的ChannelPromise,但使用有一定限制,需要小心使用 |
2.3.2、實現源碼
實現源碼如下:
@Override
public final ChannelFuture bind(SocketAddress localAddress) {
return tail.bind(localAddress);
}
@Override
public final ChannelFuture connect(SocketAddress remoteAddress) {
return tail.connect(remoteAddress);
}
@Override
public final ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
return tail.connect(remoteAddress, localAddress);
}
@Override
public final ChannelFuture disconnect() {
return tail.disconnect();
}
@Override
public final ChannelFuture close() {
return tail.close();
}
@Override
public final ChannelFuture deregister() {
return tail.deregister();
}
@Override
public final ChannelPipeline flush() {
tail.flush();
return this;
}
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
@Override
public final ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return tail.connect(remoteAddress, promise);
}
@Override
public final ChannelFuture connect(
SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
return tail.connect(remoteAddress, localAddress, promise);
}
@Override
public final ChannelFuture disconnect(ChannelPromise promise) {
return tail.disconnect(promise);
}
@Override
public final ChannelFuture close(ChannelPromise promise) {
return tail.close(promise);
}
@Override
public final ChannelFuture deregister(final ChannelPromise promise) {
return tail.deregister(promise);
}
@Override
public final ChannelPipeline read() {
tail.read();
return this;
}
@Override
public final ChannelFuture write(Object msg) {
return tail.write(msg);
}
@Override
public final ChannelFuture write(Object msg, ChannelPromise promise) {
return tail.write(msg, promise);
}
@Override
public final ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
return tail.writeAndFlush(msg, promise);
}
@Override
public final ChannelFuture writeAndFlush(Object msg) {
return tail.writeAndFlush(msg);
}
@Override
public final ChannelPromise newPromise() {
return new DefaultChannelPromise(channel);
}
@Override
public final ChannelProgressivePromise newProgressivePromise() {
return new DefaultChannelProgressivePromise(channel);
}
@Override
public final ChannelFuture newSucceededFuture() {
return succeededFuture;
}
@Override
public final ChannelFuture newFailedFuture(Throwable cause) {
return new FailedChannelFuture(channel, null, cause);
}
@Override
public final ChannelPromise voidPromise() {
return voidPromise;
}
由以上源碼可知,outbound的具體實現都是交由tail(ChannelHandlerContext)來實現的。
2.4、ChannelPipeline鏈表維護
ChannelPipeline中維護了一個ChannelHandlerContext的鏈表,I/O事件通過鏈表在用戶的Handler中傳播。
2.4.1、鏈表維護接口
方法名稱 | 返回值 | 功能說明 |
---|---|---|
addFirst(String name, ChannelHandler handler) | ChannelPipeline | 將handler添加到pipeline隊列的頭部 |
addLast(String name, ChannelHandler handler) | ChannelPipeline | 將handler添加到pipeline隊列的尾部 |
addBefore(String baseName, String name, ChannelHandler handler) | ChannelPipeline | 將handler添加到baseName對應的handler之前 |
addAfter(String baseName, String name, ChannelHandler handler) | ChannelPipeline | 將handler添加到baseName對應的handler之后 |
addFirst(ChannelHandler... handlers) | ChannelPipeline | 按順序批量添加Handler到隊列頭部 |
addLast(ChannelHandler... handlers) | ChannelPipeline | 按順序批量添加Handler到隊列尾部 |
remove(ChannelHandler handler) | ChannelPipeline | 移除handler |
remove(String name) | ChannelHandler | 移除名字為name的handler |
remove(Class<T> handlerType) | ChannelPipeline | 移除類型為handlerType的handler |
removeFirst() | ChannelPipeline | 移除第一個handler |
removeLast() | ChannelPipeline | 移除最后一個handler |
replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler) | ChannelPipeline | 用newHandler替換oldHandler |
first() | ChannelHandler | 獲取第一個Handler |
firstContext() | ChannelHandlerContext | 獲取第一個Context |
last() | ChannelHandler | 獲取最后一個Handler |
lastContext() | ChannelHandlerContext | 獲取最后一個Context |
get(String name) | ChannelHandler | 通過名字獲取Handler |
context(ChannelHandler handler) | ChannelHandlerContext | 通過Handler獲取其對應的Context |
context(String name) | ChannelHandlerContext | 通過Handler的名字獲取其對應的Context |
注:以上接口中添加的頭尾不包括head節點和tail節點,這兩節點為netty框架的節點,不允許用戶修改。
2.4.2、接口實現
以下對主要接口的源碼進行分析。
addFirst():
public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
name = filterName(name, handler);
newCtx = newContext(group, name, handler);
addFirst0(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) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private void addFirst0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext nextCtx = head.next;
newCtx.prev = head;
newCtx.next = nextCtx;
head.next = newCtx;
nextCtx.prev = newCtx;
}
主要流程為:
- 檢查Handler是否在多個pipeline中重復添加。被注解為@Sharable的Handler是可以在多個pipeline中重復添加的,否則為保證線程安全,不允許在多個pipeline中添加。
- 檢查handler名字是否重復。如果添加時的name為空,則由框架自動生成name,生成規則為:[SimpleName] + "#" + [數字],數字從0累加,知道名字不重復為止。如果添加時的name不空,則檢查name是否重復,重復則拋出IllegalArgumentException異常,否則驗證通過;
- 根據pipeline、EventExecutorGroup、name、handler新建一個ChannelHandlerContext;
- 挑用addFirst0()將新建的context添加到pipeline中head的下一個節點;
- 若Channel還未在EventLoop中注冊,則注冊PendingHandlerAddedTask任務,當Channel注冊成功時,調用ChannelHandler.handlerAdded()方法;若Channel已經注冊成功則直接調用callHandlerAdded0()方法來通過管道調用所有Handler的ChannelHandler.handlerAdded()方法。
addLast():
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
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) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
addLast()的實現源碼與addFirst基本一樣,唯一區別是將handler添加的pipeline的tail節點的前一個節點。
2.5、DefaultChannelPipeline源碼分析
DefaultChannelPipeline為ChannelPipeline接口的實現。也定義了Pipeline中的head和tail節點及實現等。
2.5.1、基本屬性
private static final String HEAD_NAME = generateName0(HeadContext.class);
private static final String TAIL_NAME = generateName0(TailContext.class);
private static final FastThreadLocal<Map<Class<?>, String>> nameCaches =
new FastThreadLocal<Map<Class<?>, String>>() {
@Override
protected Map<Class<?>, String> initialValue() throws Exception {
return new WeakHashMap<Class<?>, String>();
}
};
private static final AtomicReferenceFieldUpdater<DefaultChannelPipeline, MessageSizeEstimator.Handle> ESTIMATOR =
AtomicReferenceFieldUpdater.newUpdater(
DefaultChannelPipeline.class, MessageSizeEstimator.Handle.class, "estimatorHandle");
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
private final Channel channel;
private final ChannelFuture succeededFuture;
private final VoidChannelPromise voidPromise;
private final boolean touch = ResourceLeakDetector.isEnabled();
private Map<EventExecutorGroup, EventExecutor> childExecutors;
private volatile MessageSizeEstimator.Handle estimatorHandle;
private boolean firstRegistration = true;
/**
* This is the head of a linked list that is processed by {@link #callHandlerAddedForAllHandlers()} and so process
* all the pending {@link #callHandlerAdded0(AbstractChannelHandlerContext)}.
*
* We only keep the head because it is expected that the list is used infrequently and its size is small.
* Thus full iterations to do insertions is assumed to be a good compromised to saving memory and tail management
* complexity.
*/
private PendingHandlerCallback pendingHandlerCallbackHead;
/**
* Set to {@code true} once the {@link AbstractChannel} is registered.Once set to {@code true} the value will never
* change.
*/
private boolean registered;
HEAD_NAME:head對應的Handler的名字;
TAIL_NAME:tail對應的handler的名字;
nameCaches:Handler與其name的map的緩存;
ESTIMATOR:消息中字節大小統計器;
head:pipeline隊列的頭節點,其是ChannelHandlerContext與ChannelHandler的實現。
tail:pipeline隊列的尾節點,其是ChannelHandlerContext與ChannelHandler的實現。
channel:pipeline對應的Channel;
succeededFuture:處理成功的異步結果;
voidPromise:通用的異步處理結果;
childExecutors:子執行器;
estimatorHandle:消息字節大小統計器的處理器;
firstRegistration:是否第一次注冊
pendingHandlerCallbackHead:頭節點一些事件的異步回調任務;
2.5.2、構造函數
構造函數源碼:
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
構造函數比較簡單,主要新建的succeededFuture和voidPromise異步通知,以及鏈表的頭結點(head)和尾節點(tail)。
2.5.3、HeadContext源碼解析
HeadContext為Pipeline的頭節點實現,其即時ChannelHandlerContext的實現,也是ChannelHandler的實現。
2.5.3.1、HeadContext類繼承關系
HeadContext類繼承圖:
HeadContext實現ChannelHandler的inbound接口和outbound接口,也實現了ChannelHandlerContext的inbound及outbound接口。
2.5.4、TailContext源碼解析
TailContext為pipeline的尾節點實現,其即時ChannelHandlerContext的實現,也是ChannelHandler的實現。
TailContext類繼承圖:
TailContext在實現ChannelHandlerContext接口,同時實現ChannelHandler的inbound接口。
3、ChannelHandlerContext源碼解析
ChannelHandlerContext 代表了ChannelHandler 和ChannelPipeline 之間的關聯,每當有ChannelHandler 添加到ChannelPipeline 中時,都會創建ChannelHandlerContext。ChannelHandlerContext 的主要功能是管理它所關聯的ChannelHandler 和在同一個ChannelPipeline 中的其他ChannelHandler 之間的交互。
ChannelHandlerContext中的一些接口在ChannelPipeline中也有實現,但傳播方向有一點重要的不同。如果調用Channel 或者ChannelPipeline 上的這些方法,它們將沿著整個ChannelPipeline 進行傳播。而調用位于ChannelHandlerContext上的相同方法,則將從當前所關聯的ChannelHandler 開始,并且只會傳播給位于該ChannelPipeline 中的下一個能夠處理該事件的ChannelHandler。
ChannelHandlerContext類繼承圖:
ChannelInboundInvoker:是網絡I/O的事件的統一抽象,即為inbound事件,方法都以fireXXX開頭,pipeline也實現此接口。
ChannelOutboundInvoker:是用戶線程或代碼發起的I/O操作,被稱為outbound事件。
AttributeMap:存儲屬性鍵值對;
AbstractChannelHandlerContext:ChannelHandlerContext的抽象實現類,對通用處理進行了處理;
DefaultChannelHandlerContext:ChannelHandlerContext的默認實現,netty框架即使用此實現;
HeadContext/TailContext:pipeline的頭結點和尾節點實現;
3.1、AbstractChannelHandlerContext源碼分析
AbstractChannelHandlerContext為ChannelHandlerContext的抽象實現。
3.1.1、基本屬性
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
private static final AtomicIntegerFieldUpdater<AbstractChannelHandlerContext> HANDLER_STATE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(AbstractChannelHandlerContext.class, "handlerState");
/**
* {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} is about to be called.
*/
private static final int ADD_PENDING = 1;
/**
* {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called.
*/
private static final int ADD_COMPLETE = 2;
/**
* {@link ChannelHandler#handlerRemoved(ChannelHandlerContext)} was called.
*/
private static final int REMOVE_COMPLETE = 3;
/**
* Neither {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}
* nor {@link ChannelHandler#handlerRemoved(ChannelHandlerContext)} was called.
*/
private static final int INIT = 0;
private final boolean inbound;
private final boolean outbound;
private final DefaultChannelPipeline pipeline;
private final String name;
private final boolean ordered;
// Will be set to null if no child executor should be used, otherwise it will be set to the
// child executor.
final EventExecutor executor;
private ChannelFuture succeededFuture;
// Lazily instantiated tasks used to trigger events to a handler with different executor.
// There is no need to make this volatile as at worse it will just create a few more instances then needed.
private Runnable invokeChannelReadCompleteTask;
private Runnable invokeReadTask;
private Runnable invokeChannelWritableStateChangedTask;
private Runnable invokeFlushTask;
private volatile int handlerState = INIT;
next:pipeline中的下一個ChannelHandlerContext節點;
prev:pipeline中的上一個ChannelHandlerContext節點;
inbound:標識此Context對應的Handler是否為ChannelInboundHandler類型;
outbound:標識此Context對應的Handler是否為ChannelOutboundHandler類型;
pipeline:此Context對應的Pipeline;
name:此Context的名字;
ordered:事件順序標志;
executor:事件執行線程;
succeededFuture:成功的異步處理結果;
invokeChannelReadCompleteTask:讀完成處理任務;
invokeReadTask:讀數據任務;
invokeChannelWritableStateChangedTask:Channel寫狀態變更任務;
invokeFlushTask:沖刷數據任務;
handlerState:當前Handler的狀態
handlerState有以下四種狀態:
// 初始狀態
private static final int INIT = 0;
// 對應Handler的handlerAdded方法將要被調用但還未調用
private static final int ADD_PENDING = 1;
// 對應Handler的handlerAdded方法被調用
private static final int ADD_COMPLETE = 2;
// 對應Handler的handlerRemoved方法被調用
private static final int REMOVE_COMPLETE = 3;
3.1.1、構造函數
構造函數源碼:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
boolean inbound, boolean outbound) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
this.inbound = inbound;
this.outbound = outbound;
// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
3.1.2、inbound事件
AbstractChannelHandlerContext中對inbound事件的處理大同小異,本處只對fireChannelRegistered進行分析,其他事件處理流程基本相同;
源碼:
@Override
public ChannelHandlerContext fireChannelRegistered() {
invokeChannelRegistered(findContextInbound());
return this;
}
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
private void invokeChannelRegistered() {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRegistered();
}
}
fireChannelRegistered():此方法主要是找到下個inbound類型的Context,并交由invokeChannelRegistered(final AbstractChannelHandlerContext next):靜態方法進行處理;
invokeChannelRegistered(final AbstractChannelHandlerContext next):此靜態方法主要判斷事件處理是否在執行線程中,是則直接處理;否則異步處理。同時,pipeline中也會調用此方法對注冊事件進行傳播,pipeline中fireChannelRegistered事件的處理就是調用此靜態方法,而參數為HeadContext,即從head節點開始傳播注冊事件;
invokeChannelRegistered():此方法首先判斷Context的Handler是否已經在pipeline中添加完成,完成則直接調用對應Handler的channelRegistered()方法對注冊事件進行處理;否則直接調用fireChannelRegistered()將事件交由下個inbound類型的Context處理。
3.1.3、outbound事件
與inbound事件相同,Context的outbound事件的傳播流程也大體相同,本處以bind()事件為例進行傳播流程的分析,其他事件傳播流程類似。
源碼:
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
bind(localAddress, promise);
}
}
從bind()方法可知,其主要查找下一個Context并調用invokeBind()進行處理,而invokeBind()又調用Handler的bind();Handler的bind()通用處理是沿著outbound的Context向head節點傳播,其最終調用的是pipeline中head節點的Handler的bind()方法,而head節點的bind的方法會調用底層Channel的Unsafe的bind()方法進行最終的bind()操作。
3.2、DefaultChannelHandlerContext源碼分析
DefaultChannelHandlerContext為netty的默認ChannelHandlerContext實現,其實現非常簡單。
源碼:
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
private final ChannelHandler handler;
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
}
@Override
public ChannelHandler handler() {
return handler;
}
private static boolean isInbound(ChannelHandler handler) {
return handler instanceof ChannelInboundHandler;
}
private static boolean isOutbound(ChannelHandler handler) {
return handler instanceof ChannelOutboundHandler;
}
}
3.2.1、基本屬性
handler:context對應的ChannelHandler;
3.2.1、構造函數
構造函數主要通過isInbound()方法和isOutbound()方法判斷此ChannelHandler為inbound或outbound處理器。其他處理都交由AbstractChannelHandlerContext。
相關閱讀:
Netty源碼愫讀(一)ByteBuf相關源碼學習 【http://www.lxweimin.com/p/016daa404957】
Netty源碼愫讀(二)Channel相關源碼學習【http://www.lxweimin.com/p/02eac974258e】
Netty源碼愫讀(四)ChannelHandler相關源碼學習【http://www.lxweimin.com/p/6ee0a3b9d73a】
Netty源碼愫讀(五)EventLoop與EventLoopGroup相關源碼學習【http://www.lxweimin.com/p/05096995d296】
Netty源碼愫讀(六)ServerBootstrap相關源碼學習【http://www.lxweimin.com/p/a71a9a0291f3】
參考書籍:
《Netty實戰》
《Netty權威指南》
參考博客:
http://www.lxweimin.com/p/4c35541eec10
http://www.lxweimin.com/p/0b79872eb515
http://www.lxweimin.com/p/a0a51fd79f62
http://www.wolfbe.com/detail/201609/379.html