转载

Netty源码分析6-SimpleChannelInboundHandler

应用中很常见的业务处理情况是等待一种事件发生,然后进行处理。如果使用ChannelInboundHandler则需要这样做。

public class FooHandlerextends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof Foo) {
            Foo foo = (Foo) msg;
            // do something
        } else {
            super.channelRead(ctx, msg);
        }
    }
}

这样的代码需要重复很多地方,有没有一种通用的处理方式呢,这就是SimpleChannelInboundHandler了。这种方式不再需要instanceof判断、强制类型转换等重复操作。

一个需要注意的地方是SimpleChannelInbound会在channelRead0后默认对msg进行release,即refCnt减一,这个可以通过构造函数autoRelease参数来控制。

public class FooHandlerextends SimpleChannelInboundHandler<Foo>{
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Foo foo) throws Exception {
        // do something
    }
}

SimpleChannelInboundHandler实现分析

要实现SimpleChannelInboundHandler的功能,主要要能够得到应用中声明的泛型信息,Java中获得泛型信息一般是通过genericSuperclass来获取,例如要获取ArrayList

的泛型信息String,需要这样。

((ParameterizedType)(new ArrayList<String>(){}.getClass().getGenericSuperclass())).getActualTypeArguments()[0]

还有一些其他的case要处理,例如多个泛型信息等。Netty将这些封装到了一个TypeParameterMatcher类中,方便类似判断一个对象是否是类的泛型类的对象。

这个类的主要工作在一个find0方法上,通过一个对象和它的参数化父类和一个具体类的字符串名来找到这个类。

SimpleChannelInboundHandler的构造方法中首先通过SimpleChannelInboundHandler类和”I”作为参数构造一个TypeParameterMatcher,

这样继承SimpleChannelInboundHandler就可以得到具体的I的实现了。

public abstract class SimpleChannelInboundHandler<I>extends ChannelInboundHandlerAdapter{

    private final TypeParameterMatcher matcher;
    private final boolean autoRelease;
    protected SimpleChannelInboundHandler(boolean autoRelease) {
        matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
        this.autoRelease = autoRelease;
    }

而在channelRead中通过判断msg是否属于”T”这个具体类来决定是否要调用需要子类override的channelRead0方法。

并且在最后通过判断autoRelease参数来决定是否要对msg的refCnt减一。

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

而TypeParameter是如何获取到”I”的类型的呢

下面代码省略了一些异常或其他特殊判断,也是通过getGenericSuperclass和getTypeParameters来得到的。

private static Class<?> find0(
        final Object object, Class<?> parametrizedSuperclass, String typeParamName) {

    final Class<?> thisClass = object.getClass();
    Class<?> currentClass = thisClass;
    for (;;) {
        if (currentClass.getSuperclass() == parametrizedSuperclass) {
            int typeParamIndex = -1;
            TypeVariable<?>[] typeParams = currentClass.getSuperclass().getTypeParameters();
            for (int i = 0; i < typeParams.length; i ++) {
                if (typeParamName.equals(typeParams[i].getName())) {
                    typeParamIndex = i;
                    break;
                }
            }

           TypegenericSuperType = currentClass.getGenericSuperclass();
            if (!(genericSuperType instanceof ParameterizedType)) {
                return Object.class;
            }

            Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();

           TypeactualTypeParam = actualTypeParams[typeParamIndex];
            if (actualTypeParam instanceof ParameterizedType) {
                actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType();
            }
            if (actualTypeParam instanceof Class) {
                return (Class<?>) actualTypeParam;
            }
            ...
        }
        currentClass = currentClass.getSuperclass();
        if (currentClass == null) {
            return fail(thisClass, typeParamName);
        }
    }
}
原文  https://liuzhengyang.github.io/2018/07/22/netty-6-simplechannelinboundhandler/
正文到此结束
Loading...