netty之SimpleChannelInboundHandler

netty之SimpleChannelInboundHandler


在最開始學些netty的時候,寫的服務端demo的handler,繼承的都是ChannelInboundHandlerAdapter,客戶端繼承的是SimpleChannelInboundHandler,當然最開始學的時候都是在不斷的寫demo,並不清楚爲何兩邊繼承的類還不一樣,還想過服務端handler也繼承SimpleChannelInboundHandler類,這樣就不需要每次將數據轉換成我們需要的類型了,但是後來逐漸瞭解用法後,便放棄了使用SimpleChannelInboundHandler作爲服務端處理類。

首先說ChannelInboundHandlerAdapter類,每次使用都需要將msg轉換成我們需要的類型,如下:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        System.out.println("The time server receive order : " + body + "; the counter is : " + ++counter);
        String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
        currentTime = currentTime + System.getProperty("line.separator");
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.writeAndFlush(resp);
    }

如上就是在編寫一個最簡單的demo程序的時候將msg轉化成一個字符串,然後輸出字符串,但是隻是這樣寫還是不行的,還要在pipline中添加StringDecoder的轉碼,如下:

protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
            socketChannel.pipeline().addLast(new StringDecoder());
            socketChannel.pipeline().addLast(new TimeServerHandler());
        }

這樣寫完後,在運行server程序的時候,channelRead方法就會正確的執行,不加上面吃力handler,程序會channelRead方法處一直阻塞住,不會得到正確的響應。

再看SimpleChannelInboundHandler的源碼的時候,class最上面的註釋就是:

/**
 * {@link ChannelInboundHandlerAdapter} which allows to explicit only handle a specific type of messages.
 *
 * For example here is an implementation which only handle {@link String} messages.
 *
 * <pre>
 *     public class StringHandler extends
 *             {@link SimpleChannelInboundHandler}&lt;{@link String}&gt; {
 *
 *         {@code @Override}
 *         protected void channelRead0({@link ChannelHandlerContext} ctx, {@link String} message)
 *                 throws {@link Exception} {
 *             System.out.println(message);
 *         }
 *     }
 * </pre>
 */
public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {

繼承ChannelInboundHandlerAdapter,泛型指定處理類型,用法在註釋中寫的十分清楚,因此客戶端handler的寫法則是繼承SimpleChannelInboundHandler類後,指定處理類型,實現的方法中的參數就是我們所需的類型,十分方便。

另外一個需要知道的就是,SimpleChannelInboundHandler覆蓋了channelRead方法後,釋放了資源:

 @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);
            }
        }
    }

在這釋放資源後,我們如果想傳遞到下一個handler中是沒有作用的,因此最後在服務端的程序中不要使用這個類,服務端還是使用ChannelInboundHandlerAdapter,客戶端繼承這個類進行數據處理後無需釋放掉資源,因此才知道那麼多的博客上寫的使用這兩個類是有一定講究的,服務端使用ChannelInboundHandlerAdapter,客戶端使用SimpleChannelInboundHandler。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章