Netty-EventLoopGroup笔记

AbstractBootstrap

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    static final Entry<ChannelOption<?>, Object>[] EMPTY_OPTION_ARRAY = new Entry[0];
    static final Entry<AttributeKey<?>, Object>[] EMPTY_ATTRIBUTE_ARRAY = new Entry[0];
    volatile EventLoopGroup group;
    private volatile ChannelFactory<? extends C> channelFactory;
    private volatile SocketAddress localAddress;
    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap();
    private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap();
    private volatile ChannelHandler handler;

    AbstractBootstrap() {
    }
    
    // 注意this.group只能设置一次, 这意味着group(group)方法只能被调用一次
    public B group(EventLoopGroup group) {
        ObjectUtil.checkNotNull(group, "group");
        if (this.group != null) {
            throw new IllegalStateException("group set already");
        } else {
            this.group = group;
            return this.self();
        }
    }
  }
工具类 ObjectUtil
public static <T> T checkNotNull(T arg, String text) {
        if (arg == null) {
            throw new NullPointerException(text);
        } else {
            return arg;
        }
    }
localAddress 属性

localAddress用于绑定本地终端, 有多个设值的方法:

private volatile SocketAddress localAddress;
public B localAddress(SocketAddress localAddress) {
        this.localAddress = localAddress;
        return this.self();
    }

    public B localAddress(int inetPort) {
        return this.localAddress(new InetSocketAddress(inetPort));
    }

    public B localAddress(String inetHost, int inetPort) {
        return this.localAddress(SocketUtils.socketAddress(inetHost, inetPort));
    }

    public B localAddress(InetAddress inetHost, int inetPort) {
        return this.localAddress(new InetSocketAddress(inetHost, inetPort));
    }

这些重载的localAddress(), 最终都指向了InetSocketAddress的几个构造函数.

option 属性

private final Map<ChannelOption<?>, Object> options = new LinkedHashMap();
public <T> B option(ChannelOption<T> option, T value) {
        ObjectUtil.checkNotNull(option, "option");
        synchronized(this.options) {
            if (value == null) {
                this.options.remove(option);
            } else {
                this.options.put(option, value);
            }
        }
        return this.self();
    }
private B self() {
        return this;
    }

attr 属性

private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap();
public <T> B attr(AttributeKey<T> key, T value) {
        ObjectUtil.checkNotNull(key, "key");
        if (value == null) {
            this.attrs.remove(key);
        } else {
            this.attrs.put(key, value);
        }

        return this.self();
    }

EventLoopGroup

public interface EventLoopGroup extends EventExecutorGroup {
    EventLoop next();

    ChannelFuture register(Channel var1);

    ChannelFuture register(ChannelPromise var1);

    /** @deprecated */
    @Deprecated
    ChannelFuture register(Channel var1, ChannelPromise var2);
}

handler 属性

public B handler(ChannelHandler handler) {
        this.handler = (ChannelHandler)ObjectUtil.checkNotNull(handler, "handler");
        return this.self();
    }
    
final ChannelHandler handler() {
    return this.handler;
}

channelFactory属性

新旧两个ChannelFactory

channelFactory这个属性有点麻烦, 根源在于ChannelFactory这个类,netty中有新旧两个ChannelFactory:

混合使用
但是现在的情况是内部已经转为使用新类, 对外的接口还是继续保持使用原来的旧类, 因此代码有些混乱:

private volatile ChannelFactory<? extends C> channelFactory;

final ChannelFactory<? extends C> channelFactory() {
        return this.channelFactory;
    }
    
    
// 这个方法的参数是旧的"io.netty.bootstrap.ChannelFactory",已经被标志为"@Deprecated",尽量用下面的方法

@Deprecated
    public B channelFactory(ChannelFactory<? extends C> channelFactory) {
        ObjectUtil.checkNotNull(channelFactory, "channelFactory");
        if (this.channelFactory != null) {
            throw new IllegalStateException("channelFactory set already");
        } else {
            this.channelFactory = channelFactory;
            return this.self();
        }
    }
    
    
// 这个方法是现在推荐使用的设置channelFactory的方法, 使用新类"io.netty.channel.ChannelFactory"
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
        // 但是底层的实现还是调用回上面被废弃的channelFactory()方法
        // 因为新类是继承自旧类的,所有只要简单转一下类型就好
        return this.channelFactory((ChannelFactory)channelFactory);
    }

类方法

validate()

// validate()用于检验所有的参数, 实际代码中检查的是group和channelFactory两个参数, 这两个参数必须设置不能为空:
public B validate() {
        if (this.group == null) {
            throw new IllegalStateException("group not set");
        } else if (this.channelFactory == null) {
            throw new IllegalStateException("channel or channelFactory not set");
        } else {
            return this.self();
        }
    }

register()

register()方法创建一个新的Channel并将它注册到EventLoop, 在执行前会调用validate()方法做前置检查

public ChannelFuture register() {
        this.validate();
        return this.initAndRegister();
    }

initAndRegister()是关键代码, 细细读一下:

final ChannelFuture initAndRegister() {
        Channel channel = null;

        try {
            // 创建一个新的channel 
            channel = this.channelFactory.newChannel();
            // 调用抽象方法init, 交由子类初始化
            this.init(channel);
        } catch (Throwable var3) {
            if (channel != null) {
                // 如果出错, 强行关闭这个channel
                channel.unsafe().closeForcibly();
                // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
                return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
            }

            return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }
        // 如果创建成功,则将chananel 注册到时间eventloop中
        ChannelFuture regFuture = this.config().group().register(channel);
        // 如果注册出错
        if (regFuture.cause() != null) {
            // 判断是否已经注册
            if (channel.isRegistered()) {
                // 已经注册则关闭
                channel.close();
            } else {
                // 没有注册强行关闭
                channel.unsafe().closeForcibly();
            }
        }


      // 如果代码走到这里而且promise没有失败, 那么是下面两种情况之一:
      // 1) 如果我们尝试了从event loop中注册, 那么现在注册已经完成
      //    现在可以安全的尝试 bind()或者connect(), 因为channel已经注册成功
      // 2) 如果我们尝试了从另外一个线程中注册, 注册请求已经成功添加到event loop的任务队列中等待后续执行,现在可以安全的尝试 bind()或者connect():
      //    因为 bind() 或 connect() 会在安排的注册任务之后执行
      //    而register(), bind(), 和 connect() 都被确认是同一个线程
        return regFuture;
    }

中途调用的init()方法定义如下, 后面看具体子类代码时再展开.

abstract void init(Channel var1) throws Exception;

bind()

bind()方法有多个重载, 差异只是bind操作所需的InetSocketAddress参数从何而来而已:

  1. 从属性this.localAddress来

这个时候bind()方法无需参数, 直接使用属性this.localAddress, 当前调用之前this.localAddress必须有赋值(通过函数localAddress()):

public ChannelFuture bind() {
        this.validate();
        SocketAddress localAddress = this.localAddress;
        if (localAddress == null) {
            throw new IllegalStateException("localAddress not set");
        } else {
            return this.doBind(localAddress);
        }
    }
  1. 从bind() 方法输入参数获取:

在输入参数中来直接指定localAddress:

public ChannelFuture bind(int inetPort) {
        return this.bind(new InetSocketAddress(inetPort));
    }

    public ChannelFuture bind(String inetHost, int inetPort) {
        return this.bind(SocketUtils.socketAddress(inetHost, inetPort));
    }

    public ChannelFuture bind(InetAddress inetHost, int inetPort) {
        return this.bind(new InetSocketAddress(inetHost, inetPort));
    }

    public ChannelFuture bind(SocketAddress localAddress) {
        this.validate();
        return this.doBind((SocketAddress)ObjectUtil.checkNotNull(localAddress, "localAddress"));
    }

注: 使用带参数的bind()方法, 忽略了localAddress()设定的参数. 而且也没有设置localAddress属性. 这里的差异, 后面留意.

继续看doBind()方法的细节, 这个依然是这个类的核心内容:

private ChannelFuture doBind(final SocketAddress localAddress) {
        // 调用initAndRegister() 方法,先初始化channl, 并注册到eventloop
        final ChannelFuture regFuture = this.initAndRegister();
        final Channel channel = regFuture.channel();
        // 检查注册操作是否出错
        if (regFuture.cause() != null) {
            return regFuture;
        } else if (regFuture.isDone()) { // 是否完成
            // 如果完成,此时我们知道已经注册成功, 继续bind 操作,创建一个chanelPromise();
            ChannelPromise promise = channel.newPromise();
            // 调用 doBind0() 方法继续真正的bind操作
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // 通常此时住着的future 已经注册完成,万一没有也要处理,为channel 创建一个PendingRegistrationPromise (待完成)
            final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
            // 然后给注册的future 添加一个listener,在operationComplete() 回调时,做以下操作:
            regFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    // 检查是否出错
                    if (cause != null) {
                        // 在eventloop 上注册失败,直接让Channelpromise 失败, 避免一旦我们访问channel的eventloop 导致IllegalStateException 
                        promise.setFailure(cause);
                    } else {
                        // 注册成功,调用doBind0() 方法继续真正的bind 操作
                        promise.registered();
                        AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise);
                    }

                }
            });
            return promise;
        }
    }

doBind0() 方法

private static void doBind0(final ChannelFuture regFuture, final Channel channel, final SocketAddress localAddress, final ChannelPromise promise) {
        // 此方法在channelRegistered() 方法触发前被调用
        // 让handler 有机会在他的channelRegistered() 实现中构建pipeline
        // 给channel 的eventloop 增加一个一次性任务
        channel.eventLoop().execute(new Runnable() {
            public void run() {
                if (regFuture.isSuccess()) {
                    // 如果成功则绑定localAddress 到channel 
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    // 如果不成功则设置错误到promise
                    promise.setFailure(regFuture.cause());
                }

            }
        });
    }

类Bootstrap

类Bootstrap 帮助用户帮助客户端引导Channel,bind() 方法用于无连接传输如datagram(UDP),对于常规TCP链接, 用connect() 方法。

类成员:

private static final AddressResolverGroup<?> DEFAULT_RESOLVER;
private volatile AddressResolverGroup<SocketAddress> resolver;

public Bootstrap resolver(AddressResolverGroup<?> resolver) {
        this.resolver = resolver == null ? DEFAULT_RESOLVER : resolver;
        return this;
    }

remoteAddress 属性

remoteAddress可以通过remoteAddress()方法赋值, 有多个重载方法:


public Bootstrap remoteAddress(SocketAddress remoteAddress) {
        this.remoteAddress = remoteAddress;
        return this;
    }

    public Bootstrap remoteAddress(String inetHost, int inetPort) {
        this.remoteAddress = InetSocketAddress.createUnresolved(inetHost, inetPort);
        return this;
    }

    public Bootstrap remoteAddress(InetAddress inetHost, int inetPort) {
        this.remoteAddress = new InetSocketAddress(inetHost, inetPort);
        return this;
    }

类方法:

validate() 方法

重写了validate()方法, 在调用AbstractBootstrap的validate()方法(检查group和channelFactory)外, 增加了对handler的检查:

public Bootstrap validate() {
        super.validate();
        if (this.config.handler() == null) {
            throw new IllegalStateException("handler not set");
        } else {
            return this;
        }
    }

connect() 方法

有多个connect()方法重载, 功能都是一样, 拿到输入的remoteAddress然后调用doResolveAndConnect()方法:

private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
        // 先初始化channel并注册到 event loop
        ChannelFuture regFuture = this.initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.isDone()) {
            return !regFuture.isSuccess() ? regFuture : this.doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
        } else {
            final AbstractBootstrap.PendingRegistrationPromise promise = new AbstractBootstrap.PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        promise.setFailure(cause);
                    } else {
                        promise.registered();
                        Bootstrap.this.doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
                    }

                }
            });
            return promise;
        }
    }

doResolveAndConnect0() 方法中才是真正的开始处理连接操作, 但是还是需要检查注册操作是否完成:

doResolveAndConnect0() 方法

private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
        try {
            EventLoop eventLoop = channel.eventLoop();

            AddressResolver resolver;
            try {
                resolver = this.resolver.getResolver(eventLoop);
            } catch (Throwable var9) {
                channel.close();
                return promise.setFailure(var9);
            }

            if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
                // resolver 不知道该怎么处理给定的远程地址,或者已经解析
                doConnect(remoteAddress, localAddress, promise);
                return promise;
            }

            // 开始解析远程地址
            Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);
            if (resolveFuture.isDone()) {
                Throwable resolveFailureCause = resolveFuture.cause();
                if (resolveFailureCause != null) {
                    // 解析失败,立即关闭
                    channel.close();
                    promise.setFailure(resolveFailureCause);
                } else {
                    // 解析成功开始建立连接
                    doConnect((SocketAddress)resolveFuture.getNow(), localAddress, promise);
                }

                return promise;
            }

            // 地址解析还没有完成,只能等待完成中后再做 connect, 增加一个promise 操作
            resolveFuture.addListener(new FutureListener<SocketAddress>() {
                public void operationComplete(Future<SocketAddress> future) throws Exception {
                    if (future.cause() != null) {
                        channel.close();
                        promise.setFailure(future.cause());
                    } else {
                        Bootstrap.doConnect((SocketAddress)future.getNow(), localAddress, promise);
                    }

                }
            });
        } catch (Throwable var10) {
            promise.tryFailure(var10);
        }

        return promise;
    }

异步操作就是这点比较麻烦, 总是需要一个一个future的做判断/处理, 如果没有完成还的加promise/future来依靠回调函数继续工作处理流程.

终于到了最后的doConnect()方法, 总算可以真的连接了:

doConnect()

private static void doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
        // 该方法在channelRegistered() 方法被触发前调用
        // 给我们的handler一个在它的channelRegistered()实现中构建pipeline的机会
        final Channel channel = connectPromise.channel();

        // 获取当前的channel的 eventloop 执行一次性任务
        channel.eventLoop().execute(new Runnable() {
            public void run() {
                // 注册成功
                if (localAddress == null) {
                    channel.connect(remoteAddress, connectPromise);
                } else {
                    channel.connect(remoteAddress, localAddress, connectPromise);
                }

                connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        });
    }

init(Channel channel)方法

前面看基类AbstractBootstrap时看到过, 这个init()方法是一个模板方法, 需要子类做具体实现.

看看Bootstrap是怎么做channel初始化的:

@Override
    @SuppressWarnings("unchecked")
    void init(Channel channel) throws Exception {
        // 取channel的ChannelPipeline
        ChannelPipeline p = channel.pipeline();
        // 增加当前Bootstrap的handle到ChannelPipeline中
        p.addLast(config.handler());

        // 取当前Bootstrap设置的options, 逐个设置到channel中
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }

        // 同样取当前Bootstrap的attrs, 逐个设置到channel中
        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Map.Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }
        }
    }
setChannelOptions(channel, options, logger) 方法
static void setChannelOptions(
            Channel channel, Map<ChannelOption<?>, Object> options, InternalLogger logger) {
        for (Map.Entry<ChannelOption<?>, Object> e: options.entrySet()) {
            setChannelOption(channel, e.getKey(), e.getValue(), logger);
        }
    }

总结上在init()方法中, Bootstrap只做了一个事情: 将Bootstrap中保存的信息(handle/options/attrs)设置到新创建的channel

clone() 方法

深度克隆当前Bootstrap对象,有完全一样的配置,但是使用给定的EventLoopGroup。

这个方法适合用相同配置创建多个Channel。

public Bootstrap clone(EventLoopGroup group) {
        Bootstrap bs = new Bootstrap(this);
        bs.group = group;
        return bs;
    }

ServerBootstrap类

类ServerBootstrap用于帮助服务器端引导ServerChannel.

ServerBootstrap除了处理ServerChannel外, 还需要处理从ServerChannel下创建的Channel.Netty中称这两个关系为parent和child.

类定义

public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {}

类属性 childGroup

childGroup属性用于指定处理客户端连接的EventLoopGroup, 设置的方式有两种:

  • group(parentGroup, childGroup)方法用于单独设置parentGroup, childGroup, 分别用于处理ServerChannel和Channel.
  • group(group)方法设置parentGroup, childGroup为使用同一个EventLoopGroup. 注意这个方法覆盖了基类的方法.

private volatile EventLoopGroup childGroup;

@Override
    public ServerBootstrap group(EventLoopGroup group) {
        return group(group, group);
    }

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (childGroup == null) {
            throw new NullPointerException("childGroup");
        }
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }
    
@Deprecated
    public EventLoopGroup childGroup() {
        return childGroup;
    }

childOptions/childAttrs/childHandler属性

这三个属性和parent的基本对应, 设值方法和检验都是一模一样的:

private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();

private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();

private volatile ChannelHandler childHandler;

类方法

init() 方法

ServerBootstrap的init(channel)方法相比Bootstrap的要复杂一些, 除了设置options/attrs/handler到channel外, 还需要为child设置childGroup, childHandler, childOptions, childAttrs:

@Override
    void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }

        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

ServerBootstrapAcceptor的实现, 主要看channelRead()方法:

private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
        @Override
        @SuppressWarnings("unchecked")
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            // 获取child channel
            final Channel child = (Channel) msg;
            // 设置childHandler到child channel
            child.pipeline().addLast(childHandler);
            // 设置childOptions到child channel
            setChannelOptions(child, childOptions, logger);
            // 设置childAttrs到child channel
            for (Map.Entry<AttributeKey<?>, Object> e: childAttrs) {
                child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }
            // 将child channel注册到childGroup
            try {
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

        private static void forceClose(Channel child, Throwable t) {
            child.unsafe().closeForcibly();
            logger.warn("Failed to register an accepted channel: {}", child, t);
        }
    }

EventLoop

EventExecutorGroup 类

EventExecutorGroup和EventExecutor的关系是父子关系或者管理者与被管理者的关系:

package io.netty.util.concurrent;
public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> {}

EventExecutorGroup继承自jdk java.util.concurrent包下的ScheduledExecutorService, 这意味着EventExecutorGroup本身就是一个标准的jdk executor, 提供定时任务的支持.

EventLoopGroup

public interface EventLoopGroup extends EventExecutorGroup {
    EventLoop next();

    ChannelFuture register(Channel var1);

    ChannelFuture register(ChannelPromise var1);

    /** @deprecated */
    @Deprecated
    ChannelFuture register(Channel var1, ChannelPromise var2);
}

ChannelFuture

public interface ChannelFuture extends Future<Void> {
    Channel channel();

    ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> var1);

    ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... var1);

    ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> var1);

    ChannelFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... var1);

    ChannelFuture sync() throws InterruptedException;

    ChannelFuture syncUninterruptibly();

    ChannelFuture await() throws InterruptedException;

    ChannelFuture awaitUninterruptibly();

    boolean isVoid();
}

以Bootstrap 为例

void init(Channel channel) {
        // channel 初始化时 分配一个pipeline
        ChannelPipeline p = channel.pipeline();
        // pipeline 增加handler
        p.addLast(new ChannelHandler[]{this.config.handler()});
        setChannelOptions(channel, this.newOptionsArray(), logger);
        setAttributes(channel, (Entry[])this.attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
    }

在这里插入图片描述

pipeline 并不直接处理handler,而是交给context处理

ChannelHandler 接口

public interface ChannelHandler {
    void handlerAdded(ChannelHandlerContext var1) throws Exception;

    void handlerRemoved(ChannelHandlerContext var1) throws Exception;

    /** @deprecated */
    @Deprecated
    void exceptionCaught(ChannelHandlerContext var1, Throwable var2) throws Exception;

    @Inherited
    @Documented
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Sharable {
    }
}

@ChannelHandler.Sharable 注解 表示可以将带注释的 ChannelHandler 的同一个实例多次添加到一个或多个 ChannelPipelines 中而无需竞争条件。如果未指定此注释,则每次将其添加到管道时都必须创建一个新的处理程序实例,因为它具有非共享状态,例如成员变量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值