1. 程式人生 > >netty原始碼分析之-SimpleChannelInboundHandler與ChannelInboundHandlerAdapter詳解(6)

netty原始碼分析之-SimpleChannelInboundHandler與ChannelInboundHandlerAdapter詳解(6)

每一個Handler都一定會處理出站或者入站(也可能兩者都處理)資料,例如對於入站的Handler可能會繼承SimpleChannelInboundHandler或者ChannelInboundHandlerAdapter,而SimpleChannelInboundHandler又是繼承於ChannelInboundHandlerAdapter,最大的區別在於SimpleChannelInboundHandler會對沒有外界引用的資源進行一定的清理,並且入站的訊息可以通過泛型來規定。

對於兩者關係:

public abstract class SimpleChannelInboundHandler
<I> extends ChannelInboundHandlerAdapter

對於ChannelInboundHandlerAdapter的實現,會實現ChannelInboundHandler中的所有方法:

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler

但是我們可能只會重寫一些我們感興趣的方法來處理資料,這裡使用的是介面卡模式

對於SimpleChannelInboundHandler中:

    @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { boolean release = true; try { if (acceptInboundMessage(msg)) { @SuppressWarnings("unchecked") I imsg = (I) msg; channelRead0(ctx, imsg); } else
{ release = false; ctx.fireChannelRead(msg); } } finally { if (autoRelease && release) { ReferenceCountUtil.release(msg); } } } protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;

因此我們繼承SimpleChannelInboundHandler後,處理入站的資料我們只需要重新實現channelRead0方法,當channelRead真正被呼叫的時候我們的邏輯才會被處理。這裡使用的是模板模式,讓主要的處理邏輯保持不變,讓變化的步驟通過介面實現來完成

值得注意的是對於SimpleChannelInboundHandler入站的資料,當被讀取之後可能會執行ReferenceCountUtil.release(msg)釋放資源。底層是實現ReferenceCounted,當新的物件初始化的時候計數為1,retain()方法實現其他地方的引用計數加1,release()方法實現應用減一,當計數減少到0的時候會被顯示清除,再次訪問被清除的物件會出現訪問衝突。因此,當我們實現自己的Handler的時候如果希望將客戶端傳送過來的資料傳送到客戶端,可能在上述finally中已經釋放了資源(writeAndFlush是非同步處理),所以會出現異常情況。

但是當我們實現的是ChannelInboundHandler類的時候,重寫channelRead方法時,需要釋放ByteBuf相關的記憶體,可以使用Netty提供了一個工具方法,ReferenceCountUtil.release()