一、生成serversocketchannel
ServerBootstrap設定channel類型 bootstrap.channel(NioServerSocketChannel.class)時,ServerBootstrap的父類AbstractBootstrap的初始ChannelFactory的對象,ChannelFactory的作用是生成ServerSocketChannel對象,channel方法代碼:
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new BootstrapChannelFactory<C>(channelClass));
}
BootstrapChannelFactory為AbstractBootstrap的内部類。
二、将serverchannel注冊到selector
ServerBootstrap在綁定端口(bootstrap.bind(8080))時,調用AbstractBootstrap的initAndRegister方法:
final ChannelFuture initAndRegister() {
final Channel channel = channelFactory().newChannel();//(1)
try {
init(channel);//(2)
} catch (Throwable t) {
channel.unsafe().closeForcibly();
return channel.newFailedFuture(t);
}
ChannelPromise regPromise = channel.newPromise();//(3)
group().register(channel, regPromise);//(4)
if (regPromise.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regPromise;
}
1、調用ChannelFactory對象生成ServerBootstrap 的channel(Class<? extends C> channelClass)方法中設定的channelClass對象即NioServerSocketChannel對象,也就是Netty重新封裝過的ServerSocketChannel對象,至于Netty為什麼要封裝ServerSocketChannel後面章節再寫。
2、 初化NioServerSocketChannel對象,将我們在建立ServerBootstrap對象中設定的option 和attr值設定到NioServerSocketChannel對象中的config和arrs屬性中。
3、生成ChannelPromise對象,這個對象主要是對channel的注冊狀态進行監聽
4、 取eventLoop設定到channel中,并調用AbstractChannel$AbstractUnsafe的register0方法獎channel注冊到eventLoop中的selector,并将ChannelPromise狀态設定為成功:
private void register0(ChannelPromise promise) {
try {
// check if the channel is still open as it could be closed in the mean time when the register
// call was outside of the eventLoop
if (!ensureOpen(promise)) {
return;
}
doRegister(); //将serverchannel注冊到selector中
registered = true;
promise.setSuccess();
pipeline.fireChannelRegistered();
if (isActive()) {
pipeline.fireChannelActive();
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
if (!promise.tryFailure(t)) {
logger.warn(
"Tried to fail the registration promise, but it is complete already. " +
"Swallowing the cause of the registration failure:", t);
}
}
}
三、綁定端口
通過initAndRegister方法将serverchannel注冊到selector後調用doBind0方法注冊端口
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() { //(1)
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}