netty源码解解析(4.0)-3 Channel的抽象实现
生活随笔
收集整理的這篇文章主要介紹了
netty源码解解析(4.0)-3 Channel的抽象实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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和eventLoop綁定,eventLoop線程就是I/O線程。 確保真正的register操作在I/O線程中執行。 確保每個channel的register操作只執行一次。 真正的register操作執行成功后, 觸發channelRegistered事件,如果channel此時仍處于active狀態,觸發channelActive事件,并確保這些事件只觸發一次。 真正的register操作執行成功后, 如果channel此時仍處于active狀態,并且channel的配置支持autoRead, 則執行beginRead操作,讓eventLoop可以自動觸發channel的read事件。 bind實現 @Override public final void bind(final SocketAddress localAddress, final ChannelPromise promise) { assertEventLoop(); if (!promise.setUncancellable() || !ensureOpen(promise)) { return; } // See: https://github.com/netty/netty/issues/576 if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() && !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) { // Warn a user about the fact that a non-root user can't receive a // broadcast packet on *nix if the socket is bound on non-wildcard address. logger.warn( "A non-root user can't receive a broadcast packet if the socket " + "is not bound to a wildcard address; binding to a non-wildcard " + "address (" + localAddress + ") anyway as requested."); } //先保存是否active的狀態 boolean wasActive = isActive(); try { doBind(localAddress); //調用doBind, 需要子類實現這個方法完成真正的bind操作 } catch (Throwable t) { safeSetFailure(promise, t); closeIfClosed(); return; } if (!wasActive && isActive()) { //如果執行完doBind后從非active狀態變成active裝,則觸發channelActive事件 invokeLater(new Runnable() { @Override public void run() { pipeline.fireChannelActive(); } }); } safeSetSuccess(promise); } bind語義:
- 進一步明確接口的語意。
- 簡化Channel接口的實現。
- 調用抽象方法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還給你。 |
轉載于:https://www.cnblogs.com/brandonli/p/9949730.html
總結
以上是生活随笔為你收集整理的netty源码解解析(4.0)-3 Channel的抽象实现的全部內容,希望文章能夠幫你解決所遇到的問題。