Netty ChannelHandler之概述

語言: CN / TW / HK

ChannelHandler(管道處理器)其工作模式類似於Java Servlet過濾器,負責對I/O事件或者I/O操作進行攔截處理。採用事件的好處是,ChannelHandler可以選擇自己感興趣的事件進行處理,也可以對不感興趣的事件進行透傳或者終止。

ChannelHandler介面

基於ChannelHandler介面,使用者可以方便實現自己的業務,比如記錄日誌、編解碼、資料過濾等。ChannelHandler介面定義如下:

package io.netty.channel;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

 

public interface ChannelHandler {

    void handlerAdded(ChannelHandlerContext ctx) throws Exception;

    void handlerRemoved(ChannelHandlerContext ctx) throws Exception;

    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

    @Inherited
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Sharable {

    }

}

ChannelHandler介面定義比如簡單,只有三個方法:

  • handlerAdded方法在ChannelHandler被新增到實際上下文中並準備好處理事件後呼叫。
  • handlerRemoved方法在ChannelHandler從實際上下文中移除後呼叫,表明它不再處理事件。
  • exceptionCaught方法會在丟擲Throwable類後呼叫。

還有一個Sharable註解,該註解用於表示多個ChannelPipeline可以共享同一個ChannelHandler。

正式因為ChannelHandler介面過於簡單,我們在實際開發中,不會直接實現ChannelHandler介面,因此,Netty提供了ChannelHandlerAdapter抽象類。

ChannelHandlerAdapter抽象類

ChannelHandlerAdapter抽象類核心程式碼如下:

package io.netty.channel;

import io.netty.util.internal.InternalThreadLocalMap;
import java.util.Map;
import java.util.WeakHashMap;

public abstract class ChannelHandlerAdapter implements ChannelHandler {

    boolean added;

    public boolean isSharable() {
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);

        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // NOOP
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // NOOP
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }

}

ChannelHandlerAdapter對exceptionCaught方法做了實現,並提供了isSharable方法。需要注意的是,ChannelHandlerAdapter是抽象類,使用者可以自由的選擇是否要覆蓋ChannelHandlerAdapter類的實現。如果對某個方法感興趣,直接覆蓋掉這個方法即可,這樣程式碼就變得簡單清晰。

ChannelHandlerAdapter抽象類提供了兩個子類ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter用於針對出站事件、入站事件的進行處理。其中ChannelInboundHandlerAdapter實現了ChannelInboundHandler介面,而ChannelOutboundHandlerAdapter實現了ChannelOutboundHandler介面。

在實際開發過程中,我們的自定義的ChannelHandler多數是繼承自ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter類或者是這兩個類的子類。比如在前面章節中所涉及的編解碼器ByteToMessageDecoder、MessageToMessageDecoder、MessageToByteEncoder、MessageToMessageEncoder等,就是這兩個類的子類。

參考引用