SimpleChannelInboundHandler與ChannelInboundHandlerAdapter

每一個(gè)Handler都一定會(huì)處理出站或者入站(也可能兩者都處理)數(shù)據(jù),例如對(duì)于入站的Handler可能會(huì)繼承SimpleChannelInboundHandler或者ChannelInboundHandlerAdapter,而SimpleChannelInboundHandler又是繼承于ChannelInboundHandlerAdapter,最大的區(qū)別在于SimpleChannelInboundHandler會(huì)對(duì)沒(méi)有外界引用的資源進(jìn)行一定的清理,并且入站的消息可以通過(guò)泛型來(lái)規(guī)定。

對(duì)于兩者關(guān)系:

public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter

對(duì)于ChannelInboundHandlerAdapter的實(shí)現(xiàn),會(huì)實(shí)現(xiàn)ChannelInboundHandler中的所有方法:

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler

但是我們可能只會(huì)重寫(xiě)一些我們感興趣的方法來(lái)處理數(shù)據(jù),這里使用的是適配器模式

對(duì)于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后,處理入站的數(shù)據(jù)我們只需要重新實(shí)現(xiàn)channelRead0方法,當(dāng)channelRead真正被調(diào)用的時(shí)候我們的邏輯才會(huì)被處理。這里使用的是模板模式,讓主要的處理邏輯保持不變,讓變化的步驟通過(guò)接口實(shí)現(xiàn)來(lái)完成

值得注意的是對(duì)于SimpleChannelInboundHandler入站的數(shù)據(jù),當(dāng)被讀取之后可能會(huì)執(zhí)行ReferenceCountUtil.release(msg)釋放資源。底層是實(shí)現(xiàn)ReferenceCounted,當(dāng)新的對(duì)象初始化的時(shí)候計(jì)數(shù)為1,retain()方法實(shí)現(xiàn)其他地方的引用計(jì)數(shù)加1,release()方法實(shí)現(xiàn)應(yīng)用減一,當(dāng)計(jì)數(shù)減少到0的時(shí)候會(huì)被顯示清除,再次訪問(wèn)被清除的對(duì)象會(huì)出現(xiàn)訪問(wèn)沖突。因此,當(dāng)我們實(shí)現(xiàn)自己的Handler的時(shí)候如果希望將客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)發(fā)送到客戶端,可能在上述finally中已經(jīng)釋放了資源(writeAndFlush是異步處理),所以會(huì)出現(xiàn)異常情況。

但是當(dāng)我們實(shí)現(xiàn)的是ChannelInboundHandler類的時(shí)候,重寫(xiě)channelRead方法時(shí),需要釋放ByteBuf相關(guān)的內(nèi)存,可以使用Netty提供了一個(gè)工具方法,ReferenceCountUtil.release()

如果在channelRead中寫(xiě)了ctx.write(接收到的內(nèi)容),由于write是異步的,可能在channelRead返回之后,仍然沒(méi)有完成,為此,擴(kuò)展了ChannelInboundHandlerAdapter,其在這個(gè)時(shí)間點(diǎn)上不會(huì)釋放消息,消息在channelReadComplete(),當(dāng)writeAndFlush方法被調(diào)用時(shí)釋放。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容