首先先来看一段netty的服务端代码
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
bossGroup.next();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast("http-decoder",
new HttpRequestDecoder());
}
});
ChannelFuture future = b.bind(new InetSocketAddress(port)).sync();(阻塞直到bind完成)
System.out.println("HTTP订购服务器启动,网址是 : " + "http://localhost:"
+ port);
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
在服务端,会新建两个EventLoopGroup,一个是bossGroup,用来处理accept操作,一个是workerGroup用来处理Channel的IO及event事件处理,接下来是对ServerBootstrap一系列变量进行设置的操作。
重点来看ChannelFuture future = b.bind(new InetSocketAddress(port)).sync()这一句, 这一句即NIO中注册ServerChannel注册到Selector中的操作。我们来进入bind方法详细了解下netty的引导过程:
netty引导分客户端和服务端两种(类分别是Bootstrap和ServerBootstrap),两者都继承自AbstratBootstrap,而bind的实现就是在AbstratBootstrap中,来看看这段代码
public ChannelFuture bind(SocketAddress localAddress) {
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress);
}
前面是检查操作,具体实现在doBind()中
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
............
}
先屏蔽后面的代码,重点来看initAndRegister()
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//1、生成一个新的Channel,因为在设置引导时设置的Channel类是NioServerSocketChannel.class,所以这里生成了一个NioServerSocketChannel实例
channel = channelFactory.newChannel();
//2、对NioServerSocketChannel进行一些初始化操作
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
//3、重中之重,把channel注册到selector中
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
1、生成一个新的Channel,因为在设置引导时设置的Channel类是NioServerSocketChannel.class,所以这里生成了一个NioServerSocketChannel实例。NioServerSocketChannel实现了ServerSocketChannel接口
2、对NioServerSocketChannel进行一些初始化操作。init()方法具体实现是在ServerBootstrap类中,在init中主要是对Channel的属性进行设置以及添加handler到pipeline中
3、正常流程下来,会走到ChannelFuture regFuture = config().group().register(channel); config().group()返回的是和当前ServerBootstrap绑定的bossEventLoopGroup,利用这个EventLoopGroup实例进行注册serverSocketChannel操作。这里的bossEventLoopGroup是一个NioEventLoopGroup,它继承了MultithreadEventLoopGroup(从字面可以看出这是一个多线程的EventLoopGroup)register的具体实现就是在MultithreadEventLoopGroup中,
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
next()返回一个属于当前EventLoopGroup的EventLoop,而NioEventLoop是一个单线程的线程池,继承自SingleThreadEventLoop,register方法就在这个类中实现
@Override
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
再往下看,走到AbstractChannel中的内部类AbstractUnsafe中,看到register方法,这里eventLoop.execute(new Runnable task)会把task加入到taskQueue中,并另起一个线程进行selector 的select操作
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
......
AbstractChannel.this.eventLoop = eventLoop;
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}
将当前Channel(ServerSocketChannel)的eventloop设置为之前选择的eventloop中,并且用这个eventloop线程进行register,
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
doRegister()就是进行Channel注册到Selector的方法,下面就是触发Channel Register事件,
1、invokeHandlerAddedIfNeeded() 2、fireChannelRegistered() 3、如果是第一次则触发fireChannelActive()
走完Channel的注册过程,接下来就是绑定Channel和地址的过程,怎个过程是由AbstractChannel中的bind方法完成,第一次绑定会触发fireChannelActive()事件,绑定过程是由Channel的eventloop执行,绑定完成后,整个引导过程就结束了