文章目录

0 示例代码
ServerBooktStrap是服务器的一个启动的辅助类,由于参数很多,因此使用了Builder设计模式。接下来看一下对应的方法。
1 group方法保存Reactor线程池
对于parentGroup是放在抽象方法里的,原因是客户端(BootStrap)也使用了Reactor线程池,是为了代码的复用,值得注意的是这边可以只建立一个EventLoopGroup来共享使用。
2 channel 方法指定具体Channel类型
原理很简单就是保存了构造器,当真正的使用的时候再去实例化。这里原因也是让客户端BootStrap可以重用。看一下代码:
3 option 方法设置参数
该方法用来设置TCP的一些参数。对于服务端主要设置backlog参数(默认是100),该参数指定套接口排队的最大连接个数(分为两个队列:未链接队列【第一次握手入队】和已连接队列【握手完成入队】,当进程调用accept,已连接队列队头出队)。调用option方法,将参数加入到map当中去。方法代码如下
4 handler 和 childHandler方法保存处理器
这两个方法是用来注册处理器的。区别是handler方法注册的是NioServerSocketChannel的ChannelPipeline,而childHandler是客户端接入的连接SocketChannel对应的ChannelPipelinem。用一张图更加清晰:
代码是分别:
5 pipline中添加处理器
处理器责任链,向末尾添加处理器。
6 绑定端口并启动服务器
直接来看一下doBind方法:
6.1 initAndRegister方法
该方法初始化Selector并将Channel注册到上面(类似原生NIO)。看一下代码:
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel(); // method0: 反射获取NioServerSocketChannel,其无参构造函数初始化等同于ServerSocketChannel.open()来打开Channel;并且创建NioServerSocketChannelConfig配置类
init(channel); // method1: 初始化 1.设置socket参数和channel的附加属性; 2. 添加父子handler;
} 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);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel); // method2 :注册到Reactor线程池中的多路复用器上
// 异常情况
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
6.1.0 method0 newChannel()方法
该方法在这里实际调用了NioServerSocketChannel的无参构造函数,创建了Channel(与原生NIO编程一样),并记录SelectionKey为OP_ACCEPT并创建config类和DefaultChannelPipeline类。
6.1.1 method1 init()方法
该方法被ServerBootStrap重写,主要功能:1. 设置socket参数和channel的附加属性; 2. 添加父子handler(其中ServerBootstrapAcceptor处理器用于接收线程移交客户端channel到工作reactor线程池中)代码如下:
@Override
void init(Channel channel) throws Exception {
final Map<ChannelOption<?>, Object> options = options0(); // 代码设置的TCP参数
synchronized (options) {
setChannelOptions(channel, options, logger); // channel的config类中记录所有配置的option参数
}
final Map<AttributeKey<?>, Object> attrs = attrs0(); // channel的附加属性
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
channel.attr(key).set(e.getValue()); // 绑定附加属性到channel
}
}
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
}
// 添加AbstractBootStrap中的Handler
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// 添加ServerBootstrapAcceptor处理器
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
6.1.2 method2 register方法
将channel注册到Reactor线程池里的多路复用器上。
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 (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();// 将当前(NioServerSocketChannel)注册到eventLoop中的多路复用器上
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(); // handlerAdd
safeSetSuccess(promise);
pipeline.fireChannelRegistered(); // 触发channel注册,执行处理器的channelRegistered方法
// 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(); // 触发channel active,执行处理器的channelActive 方法吧
} 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(); // 设置selectionKey.interestOps(interestOps|readInterestOp);其中readInterestOp这边是OP_ACCEPT
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
6.2 doBind0 方法
该方法主要是对channel 绑定promise,并启动reactor线程池。代码如下:
如有错误请指正,谢谢。