写自己的netty源码分析--pipeline

绪论

三个问题

  • netty是如何判断ChannelHandler类型的?
  • 对于ChannelHandler的添加应该遵循什么样的顺序?
  • 用户手动触发事件传播,不同的触发方式有什么样的的区别?

主要内容

  • pipeline的初始化
  • 添加和删除ChannelHandler
  • 事件和异常的传播

pipeline的初始化

  • pipeline在创建Channel的时候被创建;
  • pipeline节点数据结构:ChannelHandlerContext;
  • pipeline中两大哨兵:head和tail;

pipeline的创建

不管是服务端还是客户端都会实现AbstractChannel()方法。从该方法中可以看到是每一个channel都会创建一个pipeline。

protected AbstractChannel(Channel parent, ChannelId id) {
        this.parent = parent;
        this.id = id;
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }
protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);
        //创建两节点。并将其连接起来
        tail = new TailContext(this);
        head = new HeadContext(this);

        head.next = tail;
        tail.prev = head;
    }

pipeline节点数据结构:ChannelHandlerContext

该接口主要由AbstractChannelHandlerContext类实现

public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {

    /**
     * Return the {@link Channel} which is bound to the {@link ChannelHandlerContext}.
     */
    Channel channel();

    /**
     * Returns the {@link EventExecutor} which is used to execute an arbitrary task.
     */
    EventExecutor executor();

    /**
     * The unique name of the {@link ChannelHandlerContext}.The name was used when then {@link ChannelHandler}
     * was added to the {@link ChannelPipeline}. This name can also be used to access the registered
     * {@link ChannelHandler} from the {@link ChannelPipeline}.
     */
    String name();

    /**
     * The {@link ChannelHandler} that is bound this {@link ChannelHandlerContext}.
     */
    ChannelHandler handler();

    /**
     * Return {@code true} if the {@link ChannelHandler} which belongs to this context was removed
     * from the {@link ChannelPipeline}. Note that this method is only meant to be called from with in the
     * {@link EventLoop}.
     */
    boolean isRemoved();

    @Override
    ChannelHandlerContext fireChannelRegistered();

    @Override
    ChannelHandlerContext fireChannelUnregistered();

    @Override
    ChannelHandlerContext fireChannelActive();

    @Override
    ChannelHandlerContext fireChannelInactive();

    @Override
    ChannelHandlerContext fireExceptionCaught(Throwable cause);

    @Override
    ChannelHandlerContext fireUserEventTriggered(Object evt);

    @Override
    ChannelHandlerContext fireChannelRead(Object msg);

    @Override
    ChannelHandlerContext fireChannelReadComplete();

    @Override
    ChannelHandlerContext fireChannelWritabilityChanged();

    @Override
    ChannelHandlerContext read();

    @Override
    ChannelHandlerContext flush();

    /**
     * Return the assigned {@link ChannelPipeline}
     */
    ChannelPipeline pipeline();

    /**
     * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
     */
    ByteBufAllocator alloc();

    /**
     * @deprecated Use {@link Channel#attr(AttributeKey)}
     */
    @Deprecated
    @Override
    <T> Attribute<T> attr(AttributeKey<T> key);

    /**
     * @deprecated Use {@link Channel#hasAttr(AttributeKey)}
     */
    @Deprecated
    @Override
    <T> boolean hasAttr(AttributeKey<T> key);
}

pipeline中两大哨兵:head和tail

tail = new TailContext(this);
head = new HeadContext(this);

tail

主要做到是一些收尾的工作,若是有异常没捕获会打印异常信息;若是有信息没处理,会建议你去处理。

final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {

        TailContext(DefaultChannelPipeline pipeline) {
            super(pipeline, null, TAIL_NAME, true, false);  //设置一些节点属性
            setAddComplete();                              //标识节点已经设置完成
        }
        ......

进入super()方法:
 AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
                                  boolean inbound, boolean outbound) {
        this.name = ObjectUtil.checkNotNull(name, "name");
        this.pipeline = pipeline;
        this.executor = executor;
        this.inbound = inbound;   //设置该pipeline是入站
        this.outbound = outbound; //设置该pipeline是出站
        // Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
        ordered = executor == null || executor instanceof OrderedEventExecutor;
    }

该TailContext类中的一些方法

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            onUnhandledInboundException(cause);
        }
        //在上层的handler中异常没有被捕获,最终会在tail这里打印异常信息
        protected void onUnhandledInboundException(Throwable cause) {
        try {
            logger.warn(
                    "An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
                            "It usually means the last handler in the pipeline did not handle the exception.",
                    cause);
        } finally {
            ReferenceCountUtil.release(cause);
        }
    }
     
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            onUnhandledInboundMessage(msg);
        }
        //生成的消息没有被处理,最终到tail这里会提醒建议你去检查一下pipeline的配置,最终通过release方式释放掉
        protected void onUnhandledInboundMessage(Object msg) {
        try {
            logger.debug(
                    "Discarded inbound message {} that reached at the tail of the pipeline. " +
                            "Please check your pipeline configuration.", msg);
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

head

主要做的是往下传播事件,进行读写操作的时候委托unsafe进行对数据进行操作。

 final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {

        private final Unsafe unsafe;  //实现对底层数据的读写

        HeadContext(DefaultChannelPipeline pipeline) {
            super(pipeline, null, HEAD_NAME, true, true);
            unsafe = pipeline.channel().unsafe(); 
            setAddComplete();
        }
        ......

 该HeadContext 类中的一些方法

        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            ctx.fireChannelActive();  //遇到一个事件,简单往下传播

            readIfIsAutoRead(); //连接创建成功之后会调用到channelActive,通过此方法注册一个
            //read事件,该连接底层对应的NioEventLoop对应的selector会轮询到一个read事件
        }

添加和删除ChannelHandler

添加ChannelHandler

  • 判断是否重复添加
  • 创建节点并添加至链表
  • 回调添加完成事件

判断是否重复添加

    @Override
    public final ChannelPipeline addLast(ChannelHandler... handlers) {  //可传入多个handler
        return addLast(null, handlers);
    }

    @Override
    public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
        if (handlers == null) {
            throw new NullPointerException("handlers");
        }

        for (ChannelHandler h: handlers) {  //遍历传入到每一个handler,使用重载的addLast方法添加
            if (h == null) {
                break;
            }
            addLast(executor, null, h);
        }

        return this;
    }
@Override
    public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);  //检查是否重复

            newCtx = newContext(group, filterName(name, handler), handler);

            addLast0(newCtx);

            // If the registered is false it means that the channel was not registered on an eventLoop yet.
            // In this case we add the context to the pipeline and add a task that will call
            // ChannelHandler.handlerAdded(...) once the channel is registered.
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                callHandlerAddedInEventLoop(newCtx, executor);
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }
 private static void checkMultiplicity(ChannelHandler handler) {
        if (handler instanceof ChannelHandlerAdapter) {  //判断是不是后面的实例
            ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
            if (!h.isSharable() && h.added) {  //首先判断是不是可共享的,再判断是否已经添加过
                throw new ChannelPipelineException(
                        h.getClass().getName() +
                        " is not a @Sharable handler, so can't be added or removed multiple times.");
            }
            h.added = true;
        }
    }

public boolean isSharable() {  //如果该类有注解Sharable,则可以被添加多次,否则返回false.
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);  //拿到Sharable的注解
            cache.put(clazz, sharable);
        }
        return sharable;
    }

创建节点并添加至链表

主要做了:判断名字是否重复;新建节点并添加到链表尾节点之前;

入口:
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);

判断名字是否重复

private String filterName(String name, ChannelHandler handler) {
        if (name == null) {
            return generateName(handler);  //名字为空,自动产生一个节点
        }
        checkDuplicateName(name);  //检查名字是否重复
        return name;
    }
    private void checkDuplicateName(String name) {
        if (context0(name) != null) {  //存在重复名字抛出异常
            throw new IllegalArgumentException("Duplicate handler name: " + name);
        }
    }

    private AbstractChannelHandlerContext context0(String name) {
        AbstractChannelHandlerContext context = head.next;
        while (context != tail) {
            if (context.name().equals(name)) {
                return context;   //存在重复名字
            }
            context = context.next;
        }
        return null;
    }

新建节点并添加到链表尾节点之前

private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {  
        return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);//新建节点
    }
private void addLast0(AbstractChannelHandlerContext newCtx) {  //添加到tail节点之前
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;
    }

补充

DefaultChannelHandlerContext(
            DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
        super(pipeline, executor, name, isInbound(handler), isOutbound(handler)); //判断channel是不是Inbound还是Outbound
        if (handler == null) {
            throw new NullPointerException("handler");
        }
        this.handler = handler;
    }
进入isInbound()和isOutbound()方法:
private static boolean isInbound(ChannelHandler handler) {
        return handler instanceof ChannelInboundHandler;
}

private static boolean isOutbound(ChannelHandler handler) {
        return handler instanceof ChannelOutboundHandler;
    }
进入super()方法:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
                                  boolean inbound, boolean outbound) {
        this.name = ObjectUtil.checkNotNull(name, "name");
        this.pipeline = pipeline;
        this.executor = executor;
        this.inbound = inbound;
        this.outbound = outbound;
        // Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
        ordered = executor == null || executor instanceof OrderedEventExecutor;
    }

回调添加完成事件 

 if (!executor.inEventLoop()) {
                callHandlerAddedInEventLoop(newCtx, executor);  //不在当前线程,直接放进任务队列里
                return this;
  }
}
callHandlerAdded0(newCtx);  //在当前线程直接执行
跟进callHandlerAddedInEventLoop()方法,其实里面还是callHandlerAdded0()方法
private void callHandlerAddedInEventLoop(final AbstractChannelHandlerContext newCtx, EventExecutor executor) {
        newCtx.setAddPending();  //设置更新状态
        executor.execute(new Runnable() {
            @Override
            public void run() {
                callHandlerAdded0(newCtx);
            }
        });
    }
进入callHandlerAdded0()方法:
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
        try {
            ctx.callHandlerAdded();
        } catch (Throwable t) {
            boolean removed = false;
            try {
                remove0(ctx);
                ctx.callHandlerRemoved();
                removed = true;
            } catch (Throwable t2) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Failed to remove a handler: " + ctx.name(), t2);
                }
            }

            if (removed) {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; removed.", t));
            } else {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; also failed to remove.", t));
            }
        }
    }
进入callHandlerAdded()方法:
final void callHandlerAdded() throws Exception {
        // We must call setAddComplete before calling handlerAdded. Otherwise if the handlerAdded method generates
        // any pipeline events ctx.handler() will miss them because the state will not allow it.
        if (setAddComplete()) {
            handler().handlerAdded(this);
        }
    }
进入setAddComplete()方法:以自旋和CAS的方式设置状态
final boolean setAddComplete() {
        for (;;) {
            int oldState = handlerState;
            if (oldState == REMOVE_COMPLETE) {
                return false;
            }
            // Ensure we never update when the handlerState is REMOVE_COMPLETE already.
            // oldState is usually ADD_PENDING but can also be REMOVE_COMPLETE when an EventExecutor is used that is not
            // exposing ordering guarantees.
            if (HANDLER_STATE_UPDATER.compareAndSet(this, oldState, ADD_COMPLETE)) {
                return true;
            }
        }
    }
进入handlerAdded()方法:
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (ctx.channel().isRegistered()) {
            // This should always be true with our current DefaultChannelPipeline implementation.
            // The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
            // surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
            // will be added in the expected order.
            if (initChannel(ctx)) {

                // We are done with init the Channel, removing the initializer now.
                removeState(ctx);
            }
        }
    }

回顾服务端启动,会创建ChannelInitializer对象,在添加完之后会调用用户的initChannel()方法,之后会使用remove()方法将自身进行删除。效果就是pipeline添加了用户自定义的handler。

进入ChannelInitializer类中的的handlerAdded()方法:
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (ctx.channel().isRegistered()) {
            // This should always be true with our current DefaultChannelPipeline implementation.
            // The good thing about calling initChannel(...) in handlerAdded(...) is that there will be no ordering
            // surprises if a ChannelInitializer will add another ChannelInitializer. This is as all handlers
            // will be added in the expected order.
            if (initChannel(ctx)) {

                // We are done with init the Channel, removing the initializer now.
                removeState(ctx);
            }
        }
    }
进入initChannel()方法:
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.add(ctx)) { // Guard against re-entrance.
            try {
                initChannel((C) ctx.channel());
            } catch (Throwable cause) {
                // Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
                // We do so to prevent multiple calls to initChannel(...).
                exceptionCaught(ctx, cause);
            } finally {
                ChannelPipeline pipeline = ctx.pipeline();
                if (pipeline.context(this) != null) {
                    pipeline.remove(this);
                }
            }
            return true;
        }
        return false;
    }
最终得到抽象方法initChannel()方法--此方法就是用户自定义实现的initChannel()方法
protected abstract void initChannel(C ch) throws Exception;

删除ChannelHandler

应用场景:权限校验

内容

  • 找到节点
  • 链表的删除
  • 回调删除Handler事件
@Override
    public final ChannelHandler remove(String name) {
        return remove(getContextOrDie(name)).handler();
    }
进入getContextOrDie()方法:
private AbstractChannelHandlerContext getContextOrDie(String name) {
        AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(name); //找到这个节点
        if (ctx == null) {
            throw new NoSuchElementException(name);
        } else {
            return ctx;
        }
    }

找到节点

 @Override
    public final ChannelHandlerContext context(ChannelHandler handler) {
        if (handler == null) {
            throw new NullPointerException("handler");
        }

        AbstractChannelHandlerContext ctx = head.next;
        for (;;) {  //遍历整个链表

            if (ctx == null) {
                return null;
            }

            if (ctx.handler() == handler) {
                return ctx;  //找到了节点,返回
            }

            ctx = ctx.next;
        }
    }

链表的删除

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
        assert ctx != head && ctx != tail;  //头节点和尾节点不能被删除

        synchronized (this) {
            remove0(ctx);

            // If the registered is false it means that the channel was not registered on an eventloop yet.
            // In this case we remove the context from the pipeline and add a task that will call
            // ChannelHandler.handlerRemoved(...) once the channel is registered.
            if (!registered) {
                callHandlerCallbackLater(ctx, false);
                return ctx;
            }

            EventExecutor executor = ctx.executor();
            if (!executor.inEventLoop()) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerRemoved0(ctx);
                    }
                });
                return ctx;
            }
        }
        callHandlerRemoved0(ctx);
        return ctx;
    }
进入remove0()方法:和链表的删除节点的方法一样
    private static void remove0(AbstractChannelHandlerContext ctx) {
        AbstractChannelHandlerContext prev = ctx.prev;
        AbstractChannelHandlerContext next = ctx.next;
        prev.next = next;
        next.prev = prev;
    }

回调删除Handler事件

if (!executor.inEventLoop()) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerRemoved0(ctx);
                    }
                });
                return ctx;
}
进入callHandlerRemoved0()方法:
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
        // Notify the complete removal.
        try {
            ctx.callHandlerRemoved();
        } catch (Throwable t) {
            fireExceptionCaught(new ChannelPipelineException(
                    ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
        }
    }
进入callHandlerRemoved()方法:
 final void callHandlerRemoved() throws Exception {
        try {
            // Only call handlerRemoved(...) if we called handlerAdded(...) before.
            if (handlerState == ADD_COMPLETE) {
                handler().handlerRemoved(this);  //调用回调方法删除
            }
        } finally {
            // Mark the handler as removed in any case.
            setRemoved();
        }
    }
进入回调方法handlerRemoved():(例子) ChannelInitializer类中的方法
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        initMap.remove(ctx);
    }
进入setRemoved()方法:
final void setRemoved() {
        handlerState = REMOVE_COMPLETE;  //设置删除完成状态
}

事件和异常的传播

  • inBound事件的传播
  • outBound事件的传播
  • 异常的传播

inBound事件的传播

  • 何为inBound事件以及ChannelInboundHandler事件
  • ChannelRead事件的传播
  • SimpleInBoundHandler处理器

何为inBound事件以及ChannelInboundHandler事件

简化版继承关系

public interface ChannelHandler {
    //handler被添加到pipeline中的一个回调
    void handlerAdded(ChannelHandlerContext ctx) throws Exception;
    //handler被pipeline删除之后的一个回调
    void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
    //出现异常的回调
    @Deprecated
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

    @Inherited
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Sharable {  //可被多个pipeline添加
        // no value
    }
}
public interface ChannelInboundHandler extends ChannelHandler {
    //回调方法,channel注册在NioEventLoop的selelctor之后回调
    void channelRegistered(ChannelHandlerContext ctx) throws Exception;
    void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
    //回调方法,channel在激活或失效之后回调
    void channelActive(ChannelHandlerContext ctx) throws Exception;
    void channelInactive(ChannelHandlerContext ctx) throws Exception;
    //回调方法,读数据之后回调
    void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
    void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
    //用户可以trigger一些自定义事件
    void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
    //channel读写状态改变
    void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
    //异常捕获回调
    @Override
    @SuppressWarnings("deprecation")
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}

 ChannelRead事件的传播

pipeline在调用fireChannelRead()事件时会从head开始往下传播。

进入fireChannelRead()方法:
    @Override
    public final ChannelPipeline fireChannelRead(Object msg) {
        AbstractChannelHandlerContext.invokeChannelRead(head, msg);
        return this;
    }
进入invokeChannelRead()方法:
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelRead(m);
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRead(m);
                }
            });
        }
    }
进入invokeChannelRead()方法:
private void invokeChannelRead(Object msg) {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRead(msg);
        }
    }
进入channelRead()方法:
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);  //将事件传播对象通过fireChannelRead进行传播
    }
进入fireChannelRead()方法:
    @Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        invokeChannelRead(findContextInbound(), msg); //寻找下一个InBoundHandler,通过invokeChannelRead传播
        return this;
    }
进入findContextInbound()方法:
private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;  //找到inboundHandler,返回节点
    }

 补充知识

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ctx.fireChannelRead(msg); //从当前节点开始传播
}
public void channelActive(ChannelHandlerContext ctx) {
    ctx.channel().pipeline().fireChannelRead("hello"); //从head节点开始传播
}
在Tail节点中,当一个消息从自定义handler往下传播时,一直没有处理,最后会到tail节点
protected void onUnhandledInboundMessage(Object msg) {
        try {
            logger.debug(
                    "Discarded inbound message {} that reached at the tail of the pipeline. " +
                            "Please check your pipeline configuration.", msg);
        } finally {
            ReferenceCountUtil.release(msg);  //若msg是byteBuf,不是String对象,最终会调用release释放
        }
    }

 SimpleInBoundHandler处理器

 应用场景

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
在handler中对msg只做了一些读写处理,而没有将msg往下传播,最终传播不到tail节点,也就没法自动释放,这时需要自己释放,若没有做这项操作,会导致内存泄露。
而SimpleChannelInboundHandler可以做到自动释放。
	}
SimpleChannelInboundHandler如何做到自动释放呢?
在类中定义了泛型SimpleChannelInboundHandler<ByteBuf>,进入该类中的channelRead()方法
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        boolean release = true;
        try {
            if (acceptInboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I imsg = (I) msg;  强制转换成byteBuf类型
                channelRead0(ctx, imsg); 抽象方法,用户在继承SimpleChannelInboundHandler时只需自己定义处理逻辑,而不需要考虑释放
            } else {
                release = false;
                ctx.fireChannelRead(msg);
            }
        } finally {
            if (autoRelease && release) {
                ReferenceCountUtil.release(msg);  最终通过release()方法释放
            }
        }
    }
}
protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;

outBound事件的传播

  • 何为outBound事件以及ChannelOutBoundHandler事件
  • write()事件的传播

何为outBound事件以及ChannelOutBoundHandler事件

接口里的方法更多是向用户主动发起的方法

public interface ChannelOutboundHandler extends ChannelHandler {
   
    void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;

    void connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception;

    void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

    
    void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

    
    void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;

    
    void read(ChannelHandlerContext ctx) throws Exception;

   
    void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;

   
    void flush(ChannelHandlerContext ctx) throws Exception;
}

write()事件的传播

OutBoundHandler事件的传播顺序和添加顺序相反,例如:A Handler先添加,但是传播时先传播B Handler。

write事件传播时是从tail节点开始的。

demo入口

public class OutBoundB extends ChannelOutboundHandlerAdapter {

	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise){
		System.out.println("OutBoundHandlerB: " + msg);
	}

	@Override
	public void handlerAdded(final ChannelHandlerContext ctx){
		ctx.executor().schedule(() -> {
			ctx.channel().write("hello");  <--入口开始
		}, 3, TimeUnit.SECONDS);
	}
}
进入AbstractChannel类中的write()方法:
public ChannelFuture write(Object msg) {
        return pipeline.write(msg);  委托pipeline进行传播
    }
进入write()方法:
public final ChannelFuture write(Object msg) {
        return tail.write(msg);   从tail节点开始
    }
进入write()方法:
public ChannelFuture write(Object msg) {
        return write(msg, newPromise());  newPromise()是一个空的回调,因为方法中并没有传入
    }
    @Override
    public ChannelFuture write(final Object msg, final ChannelPromise promise) {
        if (msg == null) {
            throw new NullPointerException("msg");
        }
        try {
            if (isNotValidPromise(promise, true)) {
                ReferenceCountUtil.release(msg);
                // cancelled
                return promise;
            }
        } catch (RuntimeException e) {
            ReferenceCountUtil.release(msg);
            throw e;
        }
        write(msg, false, promise);  <--进入这里
        return promise;
    }
进入write()方法:
private void write(Object msg, boolean flush, ChannelPromise promise) {
        AbstractChannelHandlerContext next = findContextOutbound();  找到下一个节点
        final Object m = pipeline.touch(msg, next);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {  当前线程在inEventLoop()中
            if (flush) {
                next.invokeWriteAndFlush(m, promise);
            } else {
                next.invokeWrite(m, promise);  <--flush为false,进入这里
            }
        } else {
            final AbstractWriteTask task;
            if (flush) {
                task = WriteAndFlushTask.newInstance(next, m, promise);
            }  else {
                task = WriteTask.newInstance(next, m, promise);
            }
            if (!safeExecute(executor, task, promise, m)) {  
                task.cancel();
            }
        }
    }
进入findContextOutbound()方法:
private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;  找到上一个节点
        } while (!ctx.outbound);
        return ctx;
    }
进入invokeWrite()方法:
private void invokeWrite(Object msg, ChannelPromise promise) {
        if (invokeHandler()) {
            invokeWrite0(msg, promise);  进入这里
        } else {
            write(msg, promise);
        }
进入invokeWrite0()方法:
private void invokeWrite0(Object msg, ChannelPromise promise) {
        try {
            ((ChannelOutboundHandler) handler()).write(this, msg, promise); 
            拿到当前节点对应的handler,当前节点为B,因为尾节点的上一节点是B,所以此时的handler为OutBoundB,此时会调用我们自己重写的write方法
        } catch (Throwable t) {
            notifyOutboundHandlerException(t, promise);
        }
    }
}
进入OutBoundB中的write()方法:
public class OutBoundB extends ChannelOutboundHandlerAdapter {
	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise){
		System.out.println("OutBoundHandlerB: " + msg);
		ctx.write(msg, promise);  
        消息会在这里继续向前传播,下一个节点为C,经历同样过程,然后是A,然后是head节点,
        在head节点就不会继续传播了,会调用底层的unsafe.write()方法。
        消息的传播是靠ChannelHandlerContext向前传播的。
	}
    ......
}

补充

public class OutBoundB extends ChannelOutboundHandlerAdapter {

	@Override
	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise){
		System.out.println("OutBoundHandlerB: " + msg);
		ctx.write(msg, promise);
	}

	@Override
	public void handlerAdded(final ChannelHandlerContext ctx){
		ctx.executor().schedule(() -> {
			ctx.channel().write("hello"); 需要从tail节点开始向前传播
			ctx.write("hello"); 这样写表示是从当前节点进行传播,而不需要从tail节点开始
		}, 3, TimeUnit.SECONDS);
	}
}

异常的传播

  • 异常的触发链
  • 异常处理的最佳实践

异常的触发链

异常触发顺序

入口:在InBoundHandlerB抛出一个异常时

public class InBoundHandlerB extends ChannelInboundHandlerAdapter {

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
		throw new BusinessException("from InBoundHandlerB ");  <--入口
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
		System.out.println("InboundHandlerA: exceptionCaught()");
		ctx.fireExceptionCaught(cause);
	}
}
抛出异常时父类方法中会调用fireChannelRead()方法:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }
    @Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }
    static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelRead(m);
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRead(m);
                }
            });
        }
    }

    private void invokeChannelRead(Object msg) {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelRead(this, msg);  此时是InBoundHandlerB
            } catch (Throwable t) {
                notifyHandlerException(t);  此时发生异常,进入此方法
            }
        } else {
            fireChannelRead(msg);
        }
    }

 

进入notifyHandlerException()方法:
private void notifyHandlerException(Throwable cause) {
        if (inExceptionCaught(cause)) {
            if (logger.isWarnEnabled()) {
                logger.warn(
                        "An exception was thrown by a user handler " +
                                "while handling an exceptionCaught event", cause);
            }
            return;
        }

        invokeExceptionCaught(cause); 进入此方法
    }
进入invokeExceptionCaught()方法:
private void invokeExceptionCaught(final Throwable cause) {
        if (invokeHandler()) {
            try {
                handler().exceptionCaught(this, cause);  进入此方法,此时该方法为回调方法,会进入InBoundhandlerB中的重写方法
            } catch (Throwable error) {
                if (logger.isDebugEnabled()) {
                    logger.debug(
                        "An exception {}" +
                        "was thrown by a user handler's exceptionCaught() " +
                        "method while handling the following exception:",
                        ThrowableUtil.stackTraceToString(error), cause);
                } else if (logger.isWarnEnabled()) {
                    logger.warn(
                        "An exception '{}' [enable DEBUG level for full stacktrace] " +
                        "was thrown by a user handler's exceptionCaught() " +
                        "method while handling the following exception:", error, cause);
                }
            }
        } else {
            fireExceptionCaught(cause);
        }
    }
进入InBoundhandlerB中的重写方法exceptionCaught():
public class InBoundHandlerB extends ChannelInboundHandlerAdapter {

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
		throw new BusinessException("from B");
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
		System.out.println("InboundHandlerA: exceptionCaught()");
		ctx.fireExceptionCaught(cause);  继续向下传播异常,若不进行处理,只会简单向下传播
	}
}

 

public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {
        invokeExceptionCaught(next, cause);  next是下一节点,向下传播了
        return this;
    }
同样的会进入invokeExceptionCaught()方法:
    static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {
        ObjectUtil.checkNotNull(cause, "cause");
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeExceptionCaught(cause);  进入此方法,该方法中会拿到下一节点中的重写方法,然后继续向下传播
        } else {
            try {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeExceptionCaught(cause);
                    }
                });
            } catch (Throwable t) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Failed to submit an exceptionCaught() event.", t);
                    logger.warn("The exceptionCaught() event that was failed to submit was:", cause);
                }
            }
        }
    }
最终到达tail节点,tail节点会调用exceptionCaught()方法:
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
    onUnhandledInboundException(cause);
}
protected void onUnhandledInboundException(Throwable cause) {
        try {
            logger.warn(
                    "An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
                            "It usually means the last handler in the pipeline did not handle the exception.",
                    cause);
        } finally {
            ReferenceCountUtil.release(cause);  若前面Handler未进行处理,tail节点会进行释放处理
        }
    }

异常处理的最佳实践

在最后添加一个异常处理器,按照相应的逻辑对异常进行处理。

public class ExceptionCaughtHandler extends ChannelInboundHandlerAdapter {

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		//super.exceptionCaught(ctx, cause);
		//在这里定义自己的异常处理逻辑
		//比如
		if(cause instanceof BusinessException){
			System.out.println("BusinessException");
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastThreadLocal 是 Netty 中的一个优化版 ThreadLocal 实现。与 JDK 自带的 ThreadLocal 相比,FastThreadLocal 在性能上有所提升。 FastThreadLocal 的性能优势主要体现在以下几个方面: 1. 线程安全性:FastThreadLocal 使用了一种高效的方式来保证线程安全,避免了使用锁的开销,使得在高并发场景下性能更好。 2. 内存占用:FastThreadLocal 的内部数据结构更加紧凑,占用的内存更少,减少了对堆内存的占用,提高了内存的利用效率。 3. 访问速度:FastThreadLocal 在访问时,使用了直接索引的方式,避免了哈希表查找的开销,使得访问速度更快。 在 Netty 源码中,FastThreadLocal 主要被用于优化线程的局部变量存储,提高线程之间的数据隔离性和访问效率。通过使用 FastThreadLocal,Netty 在高性能的网络通信中能够更好地管理线程的局部变量,提供更高的性能和并发能力。 引用中提到的代码片段展示了 Netty 中的 InternalThreadLocalMap 的获取方式。如果当前线程是 FastThreadLocalThread 类型的线程,那么就直接调用 fastGet 方法来获取 InternalThreadLocalMap 实例;否则,调用 slowGet 方法来获取。 fastGet 方法中,会先尝试获取线程的 threadLocalMap 属性,如果不存在则创建一个新的 InternalThreadLocalMap,并设置为线程的 threadLocalMap 属性。最后返回获取到的 threadLocalMap。 slowGet 方法中,通过调用 UnpaddedInternalThreadLocalMap.slowThreadLocalMap 的 get 方法来获取 InternalThreadLocalMap 实例。如果获取到的实例为 null,则创建一个新的 InternalThreadLocalMap,并将其设置到 slowThreadLocalMap 中。最后返回获取到的 InternalThreadLocalMap。 综上所述,FastThreadLocal 是 Netty 中为了优化线程局部变量存储而设计的一种高性能的 ThreadLocal 实现。它通过减少锁的开销、优化内存占用和加快访问速度来提升性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FastThreadLocal源码分析](https://blog.csdn.net/lvlei19911108/article/details/118021402)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Netty 高性能之道 FastThreadLocal 源码分析(快且安全)](https://blog.csdn.net/weixin_33871366/article/details/94653953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值