1.SelectableChannel的register
在nio编程中,通过ServerSocketChannel的register方法,将事件监听注册到Selector当中去,所以理论上在Netty中,肯定也有这么一个环节
public MultiplexerTimeServer(int port) {
try {
selector = Selector.open();
servChannel = ServerSocketChannel.open();
servChannel.configureBlocking(false);
servChannel.socket().bind(new InetSocketAddress(port), 1024);
servChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("The time server is start in port : " + port);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
2.AbstractChannel
我们分析的时候将断点下在SelectableChannel的register方法这里,发现调用方为AbstractNioChannel的doRegister方法
调用堆栈如下

doRegister方法
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().selector, 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
// Force the Selector to select now as the "canceled" SelectionKey may still be
// cached and not removed because no Select.select(..) operation was called yet.
eventLoop().selectNow();
selected = true;
} else {
// We forced a select operation on the selector before but the SelectionKey is still cached
// for whatever reason. JDK bug ?
throw e;
}
}
}
}
2. register方法参数
register方法的第2个参数0,表示不接受任何事件,第三个参数表示attach参数
那么总有一个地方需要初始化来接收SelectionKey.OP_ACCEPT事件
3.Channel注册到Selector的两种方式
- 一种是调用Channel的register方法,
- 第二种是设置SelectionKey的interestOps的值。Netty是用了第二种方式,通过设置SelectionKey的interestOps来注册Channel关心的事件,把实际的注册延迟了。
在AbstractNioChannel的doBeginRead方法中调用SelectionKey的interestOps方法来注册事件

@Override
protected void doBeginRead() throws Exception {
if (inputShutdown) {
return;
}
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
参考:
https://segmentfault.com/a/1190000013015303
https://blog.csdn.net/iter_zc/article/details/39396169