您的位置:首页 > 运维架构

Netty:options和configs

2015-11-26 09:51 525 查看
在使用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()获取设置,然后启动定时任务,等待超时。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: