前言
继上一篇讲完了Channel的注册和初始化后,我们看看Netty的Selector是如何创建的,以及Netty是如何对他进行优化的
正文
io.netty.channel.nio.NioEventLoop
// 在NioEventLoop初始化的时候,在构造方法里会调用openSelector()方法
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
// DISABLE_KEY_SET_OPTIMIZATION 是否禁用优化?,默认是false
if (DISABLE_KEY_SET_OPTIMIZATION) {
// 禁用优化,返回JDK的Selector
return new SelectorTuple(unwrappedSelector);
}
// 初始化JDK的Selector
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
return Class.forName("sun.nio.ch.SelectorImpl",false,PlatformDependent.getSystemClassLoader());
} catch (Throwable cause) {
return cause;
}
}
});
// 如果初始化失败,返回JDK的Selector
if (!(maybeSelectorImplClass instanceof Class) ||
!((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
if (maybeSelectorImplClass instanceof Throwable) {
Throwable t = (Throwable) maybeSelectorImplClass;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
}
return new SelectorTuple(unwrappedSelector);
}
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
// 反射拿到SelectorImpl类中Set类型的selectedKeys字段
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
// 反射拿到SelectorImpl类中Set类型的publicSelectedKeys字段
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
// 判断JDK的版本,java9及之后
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// 拿到这两个字段的偏移量
long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
long publicSelectedKeysFieldOffset = PlatformDependent.objectFieldOffset(publicSelectedKeysField);
// 震惊!如果存在的话,直接用Netty自己的SelectedSelectionKeySet把JDK的selectedKeys和publicSelectedKeys替换掉
// 优化点:JDK自带的selectedKeys是HashSet类型,Netty的selectedKeys是数组类型,在扩容性能、遍历效率、内存占用大小方面,数组都比HashSet有很大优势
if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
PlatformDependent.putObject(unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
PlatformDependent.putObject(unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
return null;
}
}
// JDK不支持的话,尝试用反射Filed.set
Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
if (cause != null) {
return cause;
}
cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
if (cause != null) {
return cause;
}
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
}
}
});
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
return new SelectorTuple(unwrappedSelector);
}
// 使用新的selectedKeySet
selectedKeys = selectedKeySet;
logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
return new SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}