Netty:options和configs

来源:互联网 发布:网络歌手香香 编辑:程序博客网 时间:2024/06/11 18:30

在使用Netty时,初始化服务端或客户端时,我们经常会看到如下代码

Bootstrap b = new Bootstrap();......b.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
通过option方法设置一些选项(参数),它其实是一个Map,维护这键值对,option方法在AbstractBootstrap类中

private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();@SuppressWarnings("unchecked")public <T> B option(ChannelOption<T> option, T value) {if (option == null) {throw new NullPointerException("option");}if (value == null) {synchronized (options) {options.remove(option);}} else {synchronized (options) {options.put(option, value);}}return (B) this;}
如果value是null,就会从options中删除这个对象,我们之前传入的ChannelOption.TCP_NODELAY,作为key值,true 作为value值。

ChannelOption有很多选项可以设置,具体可以参见Netty文档http://netty.io/4.1/api/io/netty/channel/ChannelOption.html

当我们要使用设置好的option时,其实是通过Channel的Config去访问的,那我们设置的option是怎样写入Config的呢?以NioSocketChannel为例,初始化时

public NioSocketChannel(Channel parent, SocketChannel socket) {super(parent, socket);config = new NioSocketChannelConfig(this, socket.socket());}
这里会创建一个NioSocketChannelConfig对象,然后在BootStrap的init方法中,有这样的过程

@Override@SuppressWarnings("unchecked")void init(Channel channel) throws Exception {ChannelPipeline p = channel.pipeline();......final Map<ChannelOption<?>, Object> options = options();synchronized (options) {for (Entry<ChannelOption<?>, Object> e: options.entrySet()) {try {if (!channel.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {logger.warn("Unknown channel option: " + e);}} catch (Throwable t) {logger.warn("Failed to set a channel option: " + channel, t);}}}......}
我们看到,它遍历channe的options,然后通过config对象的setOption去设置config中的属性,如DefaultChannelConfig中

    @Override    @SuppressWarnings("deprecation")    public <T> boolean setOption(ChannelOption<T> option, T value) {        validate(option, value);        if (option == CONNECT_TIMEOUT_MILLIS) {            setConnectTimeoutMillis((Integer) value);        } else if (option == MAX_MESSAGES_PER_READ) {            setMaxMessagesPerRead((Integer) value);        } else if (option == WRITE_SPIN_COUNT) {            setWriteSpinCount((Integer) value);        } else if (option == ALLOCATOR) {            setAllocator((ByteBufAllocator) value);        } else if (option == RCVBUF_ALLOCATOR) {            setRecvByteBufAllocator((RecvByteBufAllocator) value);        } else if (option == AUTO_READ) {            setAutoRead((Boolean) value);        } else if (option == AUTO_CLOSE) {            setAutoClose((Boolean) value);        } else if (option == WRITE_BUFFER_HIGH_WATER_MARK) {            setWriteBufferHighWaterMark((Integer) value);        } else if (option == WRITE_BUFFER_LOW_WATER_MARK) {            setWriteBufferLowWaterMark((Integer) value);        } else if (option == MESSAGE_SIZE_ESTIMATOR) {            setMessageSizeEstimator((MessageSizeEstimator) value);        } else {            return false;        }        return true;    }
DefaultSocketChannelConfig中道理一样。

NioSocketChannelConfig的继承关系如下

NioSocketChannelConfig extends DefaultSocketChannelConfig extends DefaultChannelConfig implements ChannelConfig

DefaultChannelConfig中是一般性的选项,NioSocketChannelConfig是与socket相关的设置,ChannelOption中以SO开头的都是与此相关的。
使用相关option时,也是通过config的getOption去获取的。当然Config对象也设置了一些属性,和这些option相关联,可以通过方法直接访问到。

    public <T> T getOption(ChannelOption<T> option) {        if (option == null) {            throw new NullPointerException("option");        }        if (option == CONNECT_TIMEOUT_MILLIS) {            return (T) Integer.valueOf(getConnectTimeoutMillis());        }        ......        return null;    }
比如我们设置超时时间ChannelOption.CONNECT_TIMEOUT_MILLIS,那么在AbstractNioChannel的connect方法中就能看到它的踪影:

        public final void connect(            ......            try {                ......                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 OneTimeTask() {                            @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);                    }                    ......                }            } catch (Throwable t) {                promise.tryFailure(annotateConnectException(t, remoteAddress));                closeIfClosed();            }        }
config().getConnectTimeoutMillis()获取设置,然后启动定时任务,等待超时。



0 0
原创粉丝点击