code-learning/netty/50-Netty 源码解析-ChannelHandler(三)之 SimpleChannelInboundHandler.md

10 KiB
Raw Permalink Blame History

精尽 Netty 源码解析 —— ChannelHandler之 SimpleChannelInboundHandler

1. 概述

在本文,我们来分享 SimpleChannelInboundHandler 处理器。考虑到 SimpleUserEventChannelHandler 和 SimpleChannelInboundHandler 的实现基本一致,所以也会在本文中分享。

如果胖友对 SimpleChannelInboundHandler 的使用不了解,请先看下 《一起学Netty之 SimpleChannelInboundHandler》 ,嘿嘿。

2. SimpleChannelInboundHandler

io.netty.channel.SimpleChannelInboundHandler ,继承 ChannelInboundHandlerAdapter 类,抽象类,处理指定类型的消息。应用程序中,我们可以实现 SimpleChannelInboundHandler 后,实现对指定类型的消息的自定义处理。

2.1 构造方法

public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {

    /**
     * 类型匹配器
     */
    private final TypeParameterMatcher matcher;
    /**
     * 使用完消息,是否自动释放
     *
     * @see #channelRead(ChannelHandlerContext, Object)
     */
    private final boolean autoRelease;

    /**
     * see {@link #SimpleChannelInboundHandler(boolean)} with {@code true} as boolean parameter.
     */
    protected SimpleChannelInboundHandler() {
        this(true);
    }

    /**
     * Create a new instance which will try to detect the types to match out of the type parameter of the class.
     *
     * @param autoRelease   {@code true} if handled messages should be released automatically by passing them to
     *                      {@link ReferenceCountUtil#release(Object)}.
     */
    protected SimpleChannelInboundHandler(boolean autoRelease) {
        // <1> 获得 matcher
        matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
        this.autoRelease = autoRelease;
    }

    /**
     * see {@link #SimpleChannelInboundHandler(Class, boolean)} with {@code true} as boolean value.
     */
    protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType) {
        this(inboundMessageType, true);
    }

    /**
     * Create a new instance
     *
     * @param inboundMessageType    The type of messages to match
     * @param autoRelease           {@code true} if handled messages should be released automatically by passing them to
     *                              {@link ReferenceCountUtil#release(Object)}.
     */
    protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType, boolean autoRelease) {
        // <2> 获得 matcher
        matcher = TypeParameterMatcher.get(inboundMessageType);
        this.autoRelease = autoRelease;
    }
    
    // ... 省略其它方法
}
  • matcher
    

    属性,有

    两种

    方式赋值。

  • autoRelease 属性,使用完消息,是否自动释放。

2.2 acceptInboundMessage

#acceptInboundMessage(Object msg) 方法,判断消息是否匹配。代码如下:

/**
 * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
 * {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
 */
public boolean acceptInboundMessage(Object msg) {
    return matcher.match(msg);
}

一般情况下,matcher 的类型是 ReflectiveMatcher( 它是 TypeParameterMatcher 的内部类 )。代码如下:

private static final class ReflectiveMatcher extends TypeParameterMatcher {
    
    /**
     * 类型
     */
    private final Class<?> type;
    
    ReflectiveMatcher(Class<?> type) {
        this.type = type;
    }
    
    @Override
    public boolean match(Object msg) {
        return type.isInstance(msg); // <1>
    }
    
}
  • 匹配逻辑,看 <1> 处,使用 Class#isInstance(Object obj) 方法。对于这个方法,如果我们定义的 I 泛型是个父类,那可以匹配所有的子类。例如 I 设置为 Object 类,那么所有消息,都可以被匹配列。

2.3 channelRead

 1: @Override
 2: public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
 3:     // 是否要释放消息
 4:     boolean release = true;
 5:     try {
 6:         // 判断是否为匹配的消息
 7:         if (acceptInboundMessage(msg)) {
 8:             @SuppressWarnings("unchecked")
 9:             I imsg = (I) msg;
10:             // 处理消息
11:             channelRead0(ctx, imsg);
12:         } else {
13:             // 不需要释放消息
14:             release = false;
15:             // 触发 Channel Read 到下一个节点
16:             ctx.fireChannelRead(msg);
17:         }
18:     } finally {
19:         // 判断,是否要释放消息
20:         if (autoRelease && release) {
21:             ReferenceCountUtil.release(msg);
22:         }
23:     }
24: }
  • 第 4 行:release 属性,是否需要释放消息。

  • 第 7 行:调用 #acceptInboundMessage(Object msg) 方法,判断是否为匹配的消息。

    • 匹配,调用 #channelRead0(ChannelHandlerContext ctx, I msg) 抽象方法,处理消息。代码如下:

      /**
       * <strong>Please keep in mind that this method will be renamed to
       * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong>
       *
       * Is called for each message of type {@link I}.
       *
       * @param ctx           the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
       *                      belongs to
       * @param msg           the message to handle
       * @throws Exception    is thrown if an error occurred
       */
      protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
      
      • 子类实现 SimpleChannelInboundHandler 类后,实现该方法,就能很方便的处理消息。
    • 不匹配,标记不需要释放消息,并触发 Channel Read 到下一个节点

  • 第 18 至 23 行:通过 release 变量 + autoRelease 属性,判断是否需要释放消息。若需要,调用 ReferenceCountUtil#release(Object msg) 方法,释放消息。😈 还是蛮方便的。

3. SimpleUserEventChannelHandler

io.netty.channel.SimpleUserEventChannelHandler ,继承 ChannelInboundHandlerAdapter 类,抽象类,处理指定事件的消息。

SimpleUserEventChannelHandler 和 SimpleChannelInboundHandler 基本一致,差别在于将指定类型的消息,改成了制定类型的事件。😈 所以,笔者就不详细解析了。

代码如下:

public abstract class SimpleUserEventChannelHandler<I> extends ChannelInboundHandlerAdapter {

    /**
     * 类型匹配器
     */
    private final TypeParameterMatcher matcher;
    /**
     * 使用完消息,是否自动释放
     *
     * @see #channelRead(ChannelHandlerContext, Object)
     */
    private final boolean autoRelease;

    /**
     * see {@link #SimpleUserEventChannelHandler(boolean)} with {@code true} as boolean parameter.
     */
    protected SimpleUserEventChannelHandler() {
        this(true);
    }

    /**
     * Create a new instance which will try to detect the types to match out of the type parameter of the class.
     *
     * @param autoRelease   {@code true} if handled events should be released automatically by passing them to
     *                      {@link ReferenceCountUtil#release(Object)}.
     */
    protected SimpleUserEventChannelHandler(boolean autoRelease) {
        matcher = TypeParameterMatcher.find(this, SimpleUserEventChannelHandler.class, "I");
        this.autoRelease = autoRelease;
    }

    /**
     * see {@link #SimpleUserEventChannelHandler(Class, boolean)} with {@code true} as boolean value.
     */
    protected SimpleUserEventChannelHandler(Class<? extends I> eventType) {
        this(eventType, true);
    }

    /**
     * Create a new instance
     *
     * @param eventType      The type of events to match
     * @param autoRelease    {@code true} if handled events should be released automatically by passing them to
     *                       {@link ReferenceCountUtil#release(Object)}.
     */
    protected SimpleUserEventChannelHandler(Class<? extends I> eventType, boolean autoRelease) {
        matcher = TypeParameterMatcher.get(eventType);
        this.autoRelease = autoRelease;
    }

    /**
     * Returns {@code true} if the given user event should be handled. If {@code false} it will be passed to the next
     * {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     */
    protected boolean acceptEvent(Object evt) throws Exception {
        return matcher.match(evt);
    }

    @Override
    public final void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 是否要释放消息
        boolean release = true;
        try {
            // 判断是否为匹配的消息
            if (acceptEvent(evt)) {
                @SuppressWarnings("unchecked")
                I ievt = (I) evt;
                // 处理消息
                eventReceived(ctx, ievt);
            } else {
                // 不需要释放消息
                release = false;
                // 触发 Channel Read 到下一个节点
                ctx.fireUserEventTriggered(evt);
            }
        } finally {
            // 判断,是否要释放消息
            if (autoRelease && release) {
                ReferenceCountUtil.release(evt);
            }
        }
    }

    /**
     * Is called for each user event triggered of type {@link I}.
     *
     * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleUserEventChannelHandler} belongs to
     * @param evt the user event to handle
     *
     * @throws Exception is thrown if an error occurred
     */
    protected abstract void eventReceived(ChannelHandlerContext ctx, I evt) throws Exception;

}

666. 彩蛋

木有彩蛋hoho 。