• Netty源码解析之Channel+Channelhandler


    Channel

    package io.netty.channel;
    
    public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable<Channel> {
    
        ChannelId id();
    
        EventLoop eventLoop();
    
        Channel parent();
    
        ChannelConfig config();
    
        boolean isOpen();
    
        boolean isRegistered();
    
        boolean isActive();
    
        ChannelMetadata metadata();
    
        SocketAddress localAddress();
    
        SocketAddress remoteAddress();
    
        ChannelFuture closeFuture();
    
        boolean isWritable();
    
        long bytesBeforeUnwritable();
    
        long bytesBeforeWritable();
    
        Unsafe unsafe();
    
        ChannelPipeline pipeline();
    
        ByteBufAllocator alloc();
    
        @Override
        Channel read();
    
        @Override
        Channel flush();
    
        interface Unsafe {
    
            RecvByteBufAllocator.Handle recvBufAllocHandle();
    
            SocketAddress localAddress();
    
            SocketAddress remoteAddress();
    
            void register(EventLoop eventLoop, ChannelPromise promise);
    
            void bind(SocketAddress localAddress, ChannelPromise promise);
    
            void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
    
            void disconnect(ChannelPromise promise);
    
            void close(ChannelPromise promise);
    
            void closeForcibly();
    
            void deregister(ChannelPromise promise);
    
            void beginRead();
    
            void write(Object msg, ChannelPromise promise);
    
            void flush();
    
            ChannelPromise voidPromise();
    
            ChannelOutboundBuffer outboundBuffer();
        }
    }
    
    
    • 实现出站触发器,channel能够主动触发出站事件
    • 提供Channel通用组件方法ChannelId、EventLoop、ChannelConfig、ChannelMetadata、ChannelPipeline、ByteBufAllocator
    • 内部Unsafe接口,为了保证Channel代码简洁,实际干活的事都交给它

    ThreadLocal VS FastThreadLocal

    • ThreadLocal使用map保存数据,并且以当前ThreadLocal对象作为key
    • FastThreadLocal使用数组保存数据,每个FastThreadLocal对象创建都会有一个数组索引
    • Netty 的FastThreadLocalRunnable处理了线程池使用时内存泄漏风险
    • JDK的ThreadLocal需要手动处理,使用线程池时忘记清理FastThreadLocal会内存泄漏
    • 推荐文章:https://www.jianshu.com/p/3fc2fbac4bb7

    ChannelOutboundBuffer

    AbstractChannel

    • 成员变量包括Unsafe、DefaultChannelPipeline、EventLoop
    • 出站事件委托给DefaultChannelPipeline
    • IO事件委托给Unsafe
    • AbstractUnsafe实现了register、bind、disconnect、close、deregister、write等方法的模版方法,实际实现doXXX由AbstractChannel提供抽象方法,交由具体子类实现

    AbstractNioChannel

    • NIO通道的抽象实现,对SocketChannel和ServerSocketChannel的抽象
    • 关联Java NIO的Channel,使用SocketChannel和ServerSocketChannel的父类SelectableChannel
    • 成员变量SelectableChannel、SelectionKey、readInterestOp
    • 读标志位,在NIO中,服务端通道创建后监听的是SelectionKey.OP_ACCEPT、而客户端通道监听的是SelectionKey.OP_READ,这里统一抽象,由子类指定读标志位。本来NIO的服务端通道是没有读这个概念,这里把服务端接受连接和客户端的读都抽象成一个概念,服务端读的是Channel,客户端读的是Buffer。

    AbstractNioByteChannel

    • readInterestOp
        protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
            super(parent, ch, SelectionKey.OP_READ);
        }
    
    • 实现ByteBuf的读写,以及事件的传递
    • 但是底层的通道是不支持Netty的ByteBuf读写的,因此提供抽象方法由子类实现读写转换
    NioSocketChannel
    • 实现JDK SocketChannel语义,桥接JDK的SocketChannel和Netty的Channel
    • 实现JDK SocketChannel底层调用,doXXX等底层相关方法实现
        @Override
        protected int doReadBytes(ByteBuf byteBuf) throws Exception {
            final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
            allocHandle.attemptedBytesRead(byteBuf.writableBytes());
            return byteBuf.writeBytes(javaChannel(), allocHandle.attemptedBytesRead());
        }
    
        @Override
        protected int doWriteBytes(ByteBuf buf) throws Exception {
            final int expectedWrittenBytes = buf.readableBytes();
            return buf.readBytes(javaChannel(), expectedWrittenBytes);
        }
    
        @Override
        protected long doWriteFileRegion(FileRegion region) throws Exception {
            final long position = region.transferred();
            return region.transferTo(javaChannel(), position);
        }
    

    AbstractNioMessageChannel

    • 实现抽象的消息读写
    • 读写操作对象的是Object
    NioServerSocketChannel
    • 实现JDK ServerSocketChannel语义
    • readInterestOp
        public NioServerSocketChannel(ServerSocketChannel channel) {
            super(null, channel, SelectionKey.OP_ACCEPT);
            config = new NioServerSocketChannelConfig(this, javaChannel().socket());
        }
    
    • 读取的msg对象实际是NioSocketChannel
        protected int doReadMessages(List<Object> buf) throws Exception {
            SocketChannel ch = SocketUtils.accept(javaChannel());
    
            try {
                if (ch != null) {
                    buf.add(new NioSocketChannel(this, ch));
                    return 1;
                }
            } catch (Throwable t) {
                logger.warn("Failed to create a new channel from an accepted socket.", t);
    
                try {
                    ch.close();
                } catch (Throwable t2) {
                    logger.warn("Failed to close a socket.", t2);
                }
            }
    
            return 0;
        }
    
    • 总结:NioServerSocketChannel、NioSocketChannel都有读的能力,NioServerSocketChannel的OP_ACCEPT被适配为读操作,读取的是NioSocketChannel。NioSocketChannel读取ByteBuf
    • Unsafe名字看不出啥,类似JDK的Unsafe,最好不要直接拿来用就对了。但是从在代码的功能来看,类似于Channel的delegate。Channel把脏活累活都给它干,而自己保证了代码的整洁性。Spring中BeanDefinitionDocumentReader和BeanDefinitionParserDelegate的关系,完全的代理,自己坐享其成。Channel中由Unsafe实现模版的方法,最核心的技术还是由Channel自己掌控,也就是doXXX方法还是调用的Channel完成,这也就是为什么Unsafe为什么是声明为内部接口的原因。所以总结一点:Channel负责对外提供一致性的接口,脏活累活给Unsafe,核心技术Channel自己掌控。

    举个例子:

    • 模版方法:io.netty.channel.nio.AbstractNioChannel.AbstractNioUnsafe
            @Override
            public final void connect(
                    final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
    
                try {
                    if (connectPromise != null) {
                        // Already a connect in process.
                        throw new ConnectionPendingException();
                    }
    
                    boolean wasActive = isActive();
                    if (doConnect(remoteAddress, localAddress)) {
                        fulfillConnectPromise(promise, wasActive);
                    } else {
                        connectPromise = promise;
                        requestedRemoteAddress = remoteAddress;
    
                        // Schedule connect timeout.
                        int connectTimeoutMillis = config().getConnectTimeoutMillis();
                        if (connectTimeoutMillis > 0) {
                            connectTimeoutFuture = eventLoop().schedule(new Runnable() {
                                @Override
                                public void run() {
                                    ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
                                    ConnectTimeoutException cause =
                                            new ConnectTimeoutException("connection timed out: " + remoteAddress);
                                    if (connectPromise != null && connectPromise.tryFailure(cause)) {
                                        close(voidPromise());
                                    }
                                }
                            }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
                        }
    
                        promise.addListener(new ChannelFutureListener() {
                            @Override
                            public void operationComplete(ChannelFuture future) throws Exception {
                                if (future.isCancelled()) {
                                    if (connectTimeoutFuture != null) {
                                        connectTimeoutFuture.cancel(false);
                                    }
                                    connectPromise = null;
                                    close(voidPromise());
                                }
                            }
                        });
                    }
                } catch (Throwable t) {
                    promise.tryFailure(annotateConnectException(t, remoteAddress));
                    closeIfClosed();
                }
            }
    
    • 抽象方法io.netty.channel.nio.AbstractNioChannel.doConnect(SocketAddress, SocketAddress)

    ChannelHandler

    package io.netty.channel;
    public interface ChannelHandler {
    
        void handlerAdded(ChannelHandlerContext ctx) throws Exception;
    
        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 {
            // no value
        }
    }
    
    

    ChannelHandlerAdapter

    package io.netty.channel;
    
    public abstract class ChannelHandlerAdapter implements ChannelHandler {
    
        boolean added;
    
        protected void ensureNotSharable() {
            if (isSharable()) {
                throw new IllegalStateException("ChannelHandler " + getClass().getName() + " is not allowed to be shared");
            }
        }
    
        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
        }
    
        @Skip
        @Override
        @Deprecated
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.fireExceptionCaught(cause);
        }
    }
    
    
    • 类适配器模式
    • 实现了Sharable注解解析缓存,提供ensureNotSharable方法

    ChannelInboundHandler

    package io.netty.channel;
    
    public interface ChannelInboundHandler extends ChannelHandler {
    
        void channelRegistered(ChannelHandlerContext ctx) throws Exception;
    
        void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
    
        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;
    
        void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
    
        void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
    
        @Override
        @SuppressWarnings("deprecation")
        void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
    }
    
    
    • 入站事件,被动触发的行为

    ChannelInboundInvoker

    package io.netty.channel;
    
    public interface ChannelInboundInvoker {
    
        ChannelInboundInvoker fireChannelRegistered();
    
        ChannelInboundInvoker fireChannelUnregistered();
    
        ChannelInboundInvoker fireChannelActive();
    
        ChannelInboundInvoker fireChannelInactive();
    
        ChannelInboundInvoker fireExceptionCaught(Throwable cause);
    
        ChannelInboundInvoker fireUserEventTriggered(Object event);
    
        ChannelInboundInvoker fireChannelRead(Object msg);
    
        ChannelInboundInvoker fireChannelReadComplete();
    
        ChannelInboundInvoker fireChannelWritabilityChanged();
    }
    
    
    • 入站事件触发器

    • 对应ChannelInboundHandler

    ChannelInboundHandlerAdapter

    package io.netty.channel;
    
    public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
    
        @Skip
        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelRegistered();
        }
    
    
        @Skip
        @Override
        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelUnregistered();
        }
    
        @Skip
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive();
        }
    
        @Skip
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelInactive();
        }
    
        @Skip
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ctx.fireChannelRead(msg);
        }
    
        @Skip
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelReadComplete();
        }
    
        @Skip
        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            ctx.fireUserEventTriggered(evt);
        }
    
        @Skip
        @Override
        public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelWritabilityChanged();
        }
    
        @Skip
        @Override
        @SuppressWarnings("deprecation")
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
                throws Exception {
            ctx.fireExceptionCaught(cause);
        }
    }
    
    
    • 类适配器
    • 默认将事件直接传递

    ChannelOutboundHandler

    package io.netty.channel;
    
    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;
    }
    
    
    • 出站事件,主动触发的行为

    ChannelOutboundInvoker

    package io.netty.channel;
    public interface ChannelOutboundInvoker {
    
        ChannelFuture bind(SocketAddress localAddress);
    
        ChannelFuture connect(SocketAddress remoteAddress);
    
        ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress);
    
        ChannelFuture disconnect();
    
        ChannelFuture close();
    
        ChannelFuture deregister();
    
        ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);
    
        ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);
    
        ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
    
        ChannelFuture disconnect(ChannelPromise promise);
    
        ChannelFuture close(ChannelPromise promise);
    
        ChannelFuture deregister(ChannelPromise promise);
    
        ChannelOutboundInvoker read();
    
        ChannelFuture write(Object msg);
    
        ChannelFuture write(Object msg, ChannelPromise promise);
    
        ChannelOutboundInvoker flush();
    
        ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);
    
        ChannelFuture writeAndFlush(Object msg);
    
        ChannelPromise newPromise();
    
        ChannelProgressivePromise newProgressivePromise();
    
        ChannelFuture newSucceededFuture();
    
        ChannelFuture newFailedFuture(Throwable cause);
    
        ChannelPromise voidPromise();
    }
    
    
    • 出站事件触发器
    • 对应ChannelOutboundHandler

    ChannelOutboundHandlerAdapter

    package io.netty.channel;
    
    public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {
    
        @Skip
        @Override
        public void bind(ChannelHandlerContext ctx, SocketAddress localAddress,
                ChannelPromise promise) throws Exception {
            ctx.bind(localAddress, promise);
        }
    
        @Skip
        @Override
        public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
                SocketAddress localAddress, ChannelPromise promise) throws Exception {
            ctx.connect(remoteAddress, localAddress, promise);
        }
    
        @Skip
        @Override
        public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise)
                throws Exception {
            ctx.disconnect(promise);
        }
    
        @Skip
        @Override
        public void close(ChannelHandlerContext ctx, ChannelPromise promise)
                throws Exception {
            ctx.close(promise);
        }
    
        @Skip
        @Override
        public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
            ctx.deregister(promise);
        }
    
        @Skip
        @Override
        public void read(ChannelHandlerContext ctx) throws Exception {
            ctx.read();
        }
    
        @Skip
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
            ctx.write(msg, promise);
        }
    
        @Skip
        @Override
        public void flush(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    }
    
    

    ChannelPipeline

    package io.netty.channel;
    public interface ChannelPipeline
            extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {
    
        ChannelPipeline addFirst(String name, ChannelHandler handler);
    
        ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);
    
        ChannelPipeline addLast(String name, ChannelHandler handler);
    
        ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);
    
        ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
    
        ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);
    
        ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
    
        ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);
    
        ChannelPipeline addFirst(ChannelHandler... handlers);
    
        ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);
    
        ChannelPipeline addLast(ChannelHandler... handlers);
    
        ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);
    
        ChannelPipeline remove(ChannelHandler handler);
    
        ChannelHandler remove(String name);
    
        <T extends ChannelHandler> T remove(Class<T> handlerType);
    
        ChannelHandler removeFirst();
    
        ChannelHandler removeLast();
    
        ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
    
        ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
    
        <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName,
                                             ChannelHandler newHandler);
    
        ChannelHandler first();
    
        ChannelHandlerContext firstContext();
    
        ChannelHandler last();
    
        ChannelHandlerContext lastContext();
    
        ChannelHandler get(String name);
    
        <T extends ChannelHandler> T get(Class<T> handlerType);
    
        ChannelHandlerContext context(ChannelHandler handler);
    
        ChannelHandlerContext context(String name);
    
        ChannelHandlerContext context(Class<? extends ChannelHandler> handlerType);
    
        Channel channel();
    
        List<String> names();
    
        Map<String, ChannelHandler> toMap();
    
        @Override
        ChannelPipeline fireChannelRegistered();
    
        @Override
        ChannelPipeline fireChannelUnregistered();
    
        @Override
        ChannelPipeline fireChannelActive();
    
        @Override
        ChannelPipeline fireChannelInactive();
    
        @Override
        ChannelPipeline fireExceptionCaught(Throwable cause);
    
        @Override
        ChannelPipeline fireUserEventTriggered(Object event);
    
        @Override
        ChannelPipeline fireChannelRead(Object msg);
    
        @Override
        ChannelPipeline fireChannelReadComplete();
    
        @Override
        ChannelPipeline fireChannelWritabilityChanged();
    
        @Override
        ChannelPipeline flush();
    }
    
    
    • 继承ChannelInboundInvoker, ChannelOutboundInvoker具有出站入站触发功能
    • 具有ChannelHandler管理功能
    • 提供ChannelHandlerContext相关方法

    DefaultChannelPipeline

    • 关键属性:

      • final AbstractChannelHandlerContext head;
      • final AbstractChannelHandlerContext tail;
      • private final Channel channel;
    • channel关联的通道

    • ChannelPipeline是一个处理器管道,也就是使用责任链模式串联多个ChannelHandler。但是并不是把用户的ChannelHandler直接串联起来,而是封装成ChannelHandlerContext,这个类见名知义,封装了ChannelHandler的上下文信息。

    • ChannelHandler构成双向链表,那么就有头和尾,Inbound事件从头传到尾,Outbound事件从尾传到头

    • 事件的传递肯定不能没有默认处理器,比如发起connect,不能在一个空链表直接丢失了,肯定要有一个兜底

    • 默认ChannelPipeline会有head和tail,负责兜底,head负责出站兜底,tail负责入站兜底。因为head是出站事件的最后一个处理器,而tail是入站事件的最后一个处理器。

    • 出站事件的兜底是head调用Unsafe完成,如io.netty.channel.DefaultChannelPipeline.HeadContext.connect(ChannelHandlerContext, SocketAddress, SocketAddress, ChannelPromise)

            @Override
            public void connect(
                    ChannelHandlerContext ctx,
                    SocketAddress remoteAddress, SocketAddress localAddress,
                    ChannelPromise promise) {
                unsafe.connect(remoteAddress, localAddress, promise);
            }
    
    • 入站事件的兜底是tail完成,负责未处理的一些资源释放,如io.netty.channel.DefaultChannelPipeline.TailContext.userEventTriggered(ChannelHandlerContext, Object)
            @Override
            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
                onUnhandledInboundUserEventTriggered(evt);
            }
    

    io.netty.channel.DefaultChannelPipeline.onUnhandledInboundUserEventTriggered(Object)

        protected void onUnhandledInboundUserEventTriggered(Object evt) {
            ReferenceCountUtil.release(evt);
        }
    
    • 用户自定义的处理器通过增删改查方法在ChannelPipeline中组成双向链表
    • head<——>ChannelHandler1<——>ChannelHandler2 …… ChannelHandlerN<——>tail

    事件传播

    • 查看ChannelPipeline接口注解

    • Inbound event propagation methods:

      • ChannelHandlerContext.fireChannelRegistered()
      • ChannelHandlerContext.fireChannelActive()
      • ChannelHandlerContext.fireChannelRead(Object)
      • ChannelHandlerContext.fireChannelReadComplete()
      • ChannelHandlerContext.fireExceptionCaught(Throwable)
      • ChannelHandlerContext.fireUserEventTriggered(Object)
      • ChannelHandlerContext.fireChannelWritabilityChanged()
      • ChannelHandlerContext.fireChannelInactive()
      • ChannelHandlerContext.fireChannelUnregistered()
    • Outbound event propagation methods:

      • ChannelHandlerContext.bind(SocketAddress, ChannelPromise)
      • ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise)
      • ChannelHandlerContext.write(Object, ChannelPromise)
      • ChannelHandlerContext.flush()
      • ChannelHandlerContext.read()
      • ChannelHandlerContext.disconnect(ChannelPromise)
      • ChannelHandlerContext.close(ChannelPromise)
      • ChannelHandlerContext.deregister(ChannelPromise)

    ChannelHandlerContext

    package io.netty.channel;
    
    public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
    
        Channel channel();
    
        EventExecutor executor();
    
        String name();
    
        ChannelHandler handler();
    
        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();
    
        ChannelPipeline pipeline();
    
        ByteBufAllocator alloc();
    
        @Deprecated
        @Override
        <T> Attribute<T> attr(AttributeKey<T> key);
    
        @Deprecated
        @Override
        <T> boolean hasAttr(AttributeKey<T> key);
    }
    
    
    • 通道处理器上下文
    • 实现出站入站触发器
    • 包含获取通道处理器上下文相关组件方法
    • Channel、EventExecutor、ChannelHandler、ChannelPipeline、ByteBufAllocator
    • 调用ChannelHandlerContext的fireXXX方法是把事件向下传播,调用ChannelPipeline的fireXXX是把事件从头或尾向下传播
  • 相关阅读:
    docker curl: (56) Recv failure: Connection reset by peer
    计算机网络,路由与DNS演示
    python向mysql插入自增字段
    洛谷P1516 青蛙的约会
    电子海图开发第三十八篇 , s57,s52标准电子海图,条件符号程序(共一百篇)
    电子海图开发第三十七篇 , s57,s52标准电子海图,绘制面命令及其示例(共一百篇)
    电子海图开发第三十六篇 , s57,s52标准电子海图,绘制线命令及其示例(共一百篇)
    电子海图开发第三十五篇 , s57,s52标准电子海图,绘制点命令及其示例(共一百篇)
    电子海图开发第三十四篇 , s57,s52标准电子海图,文本的绘制示例(共一百篇)
    电子海图开发第三十三篇 , s57,s52标准电子海图,文本的绘制(共一百篇)
  • 原文地址:https://www.cnblogs.com/zby9527/p/13163058.html
Copyright © 2020-2023  润新知