天天看點

Netty ChannelHandler之概述

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等,就是這兩個類的子類。

參考引用