版本
本次源码分析基于Netty的版本为4.1
源码分析
NioEventLoop可以视为java中的一个线程,只不过NioEventLoop处理的事件,以及内部的处理逻辑会有所不同。先看一下类的继承关系:
可以看到NioEventLoop实现了很多接口,特别是EventLoop和ScheduledExecutorService,所以NioEventLoop不仅能实现普通的task,还能实现定时task。
Selector
Netty的实现是基于Java原生的NIO的,其对原生的NIO做了很多优化,避免了某些bug,也提升了很多性能。但是底层对于网络IO事件的监听和处理也是离不开多路复用器Selector的。在NioEventLoop的构造方法中进行了Selector的初始化:
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
关键还是openSelector()方法,这里我删除了一些分支代码,剩下的做了注释,其中常量 DISABLEKEYSET_OPTIMIZATION 的定义如下,可以手工配置是否开启优化,默认是开启优化的,具体优化做了什么事可以查看下面的openSelector()分析。
private static final boolean DISABLE_KEY_SET_OPTIMIZATION = SystemPropertyUtil.getBoolean("io.netty.noKeySetOptimization", false);
netty在创建selector的时候就尝试了优化,具体优化其实是将底层的数据结构从HashSet改为了数组,可以从SelectedSelectionKeySet和SelectorImpl的源码看到这一点,这里就不列了。
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
// 根据底层的IO模型来创建一个selector,这里的selector就是java中NIO的selector
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
// 如果未开启优化则直接就返回了,SelectorTuple可以视为一个持有selector引用的句柄
if (DISABLE_KEY_SET_OPTIMIZATION) {
return new SelectorTuple(unwrappedSelector);
}
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
// 通过反射创建一个selector的具体实例
return Class.forName(
"sun.nio.ch.SelectorImpl",
false,
PlatformDependent.getSystemClassLoader());
} catch (Throwable cause) {
return cause;
}
}
});
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
// netty自己包装的一个selectKey的集合类
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// java 9 以上版本会用Unsafe类直接底层替换SelectionKeySet
}
// 利用反射将原生selector中的两个属性替换为netty自己的包装类
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;