netty原始碼解解析(4.0)-3 Channel的抽象實現
阿新 • • 發佈:2018-11-13
AbstractChannel和AbstractUnsafe抽象類
io.netty.channel.AbstractChannel
從本章開始,會有大量的篇幅涉及到程式碼分析。為了能夠清晰簡潔的地說明程式碼的結構和功能,我會用程式碼註釋+獨立段落的方式加以呈現。 所以,為你能更好地理解程式碼,請不要忽略程式碼中黑體字註釋。
AbstractChannel和AbstractUnsafe之間的關係
AbstractChannel實現了Channel介面,AbstractUnsafe實現了Unsafe。這兩個類是抽象類,他們實現了Channel和Unsafe的絕大部分介面。在AbstractChannel的實現中,每個方法都會直接或間接呼叫Unsafe對應的同名方法。所有的inbound和outbound方法都是通過pipeline間接呼叫,其他的輔助方法直接使用unsafe例項呼叫。pipline和unsafe例項在AbstractChannel的構造方法建立:
protected AbstractChannel(Channel parent) {
this.parent = parent;
unsafe = newUnsafe(); //
AbstractChannel沒有實現這個方法
pipeline = newChannelPipeline(); //
newChannelPipline的實現 return new DefaultChannelPipeline(this);
}
直接呼叫的例子:
@Override
public SocketAddress localAddres) {
SocketAddress localAddress = this.localAddress;
if (localAddress == null) {
try {
//
這裡直接呼叫了Unsafe的localAddress()方法
this.localAddress = localAddress = unsafe().localAddress();
} catch (Throwable t) {
// Sometimes fails on a closed socket in Windows.
return null;
}
}
return localAddress;
}
間接呼叫的例子
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return pipeline.bind(localAddress); //通過pipline間接呼叫Unsafe的bind方法
}
關於pipline是怎樣呼叫Unsafe方法的,會在後面的Pipline相關章節詳細分析,這裡只需記住。pipeline所有方法呼叫最終都會(如果沒有改變ChannelContextHandler的預設實現)通過使用newUnsafe建立的Unsafe例項呼叫Unsafe的同名方法(如果有的話)。
netty給出這一對Abstract實現有兩個目的:
- 進一步明確介面的語意。
- 簡化Channel介面的實現。
- 把channel和eventLoop繫結,eventLoop執行緒就是I/O執行緒。
- 確保真正的register操作在I/O執行緒中執行。
- 確保每個channel的register操作只執行一次。
- 真正的register操作執行成功後, 觸發channelRegistered事件,如果channel此時仍處於active狀態,觸發channelActive事件,並確保這些事件只觸發一次。
- 真正的register操作執行成功後, 如果channel此時仍處於active狀態,並且channel的配置支援autoRead, 則執行beginRead操作,讓eventLoop可以自動觸發channel的read事件。
- 呼叫抽象方法doBind, 它需要子類實現。
- 如果channel的狀態從非active變成active狀態,則觸發channelActive事件
- 呼叫doDeregister執行真正的deregister操作
- 根據引數可能需要觸發channelInactive事件
- 觸發channelUnregistered事件
- 呼叫doWrite方法執行真正的寫操作
- 如果寫操作失敗,呼叫close或者shutdownOutput進行善後。
方法 | 說明 |
protected abstract SocketAddress localAddress0() | 被localAddress呼叫,執行真正的獲取本地地址的操作。 |
protected abstract SocketAddress remoteAddress0() | 被remoteAddress呼叫,是真正的獲取遠端地址的操作。 |
protected abstract boolean isCompatible(EventLoop loop) | 檢查eventLoop是是否和這個Channel相容。 |
protected void doRegister() | 呼叫鏈register->register0->doRegister, 真正的註冊操作。 |
protected abstract void doBind(SocketAddress localAddress) | 被bind呼叫,執行真正繫結本地地址的操作。 |
protected abstract void doDisconnect() | 被disconnect呼叫,執行真正的斷開連線操作。 |
protected abstract void doClose() | 被close掉,執行真正的關閉channel操作。 |
protected void doShutdownOutput() | 被shutdownOutput呼叫,用來關閉output通道,使Channel不能write。它的的預設實現是呼叫doClose |
protected void doDeregister() | 被deregister呼叫,是真正的登出操作,雖然不是抽象方法,然而只有一個{}, 還是要等你來搞定。 |
protected abstract void doBeginRead() | 呼叫鏈register->register0->beginRead->doBeginRead, 實現讓eventLoop可以自動觸發read事件。 |
protected abstract void doWrite(ChannelOutboundBuffer in) | 呼叫鏈flush->flush0->doWrite, 執行真正的寫操作。 |
protected Object filterOutboundMessage(Object msg) | 被write呼叫,在訊息被放到outboundBuffer之前對訊息進行處理,預設啥事都沒幹,就是把你傳進去的msg還給你。 |