2021SC@SDUSC
一、前言
在本篇博客中,会承接上一篇博客中对服务器端的端口绑定方法的分析,继续学习剩余的内容,包括initAndRegister和dobind0等方法。
二、initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
init(channel);
} catch (Throwable t) {
if (channel != null) {
channel.unsafe().closeForcibly();
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
首先,在try语句块中完成了对channel对象的创建,这里channelFactory的具体类型是ReflectiveChannelFactory类,newChannel的具体实现如代码所示。
@Override
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
可以看到,这里实际上是通过了构造器调用无参构造函数来创建的,而构造器则是在serverbootstrap的channel方法中指定的。
//AbstractBootstrap类的channel方法,用于指定Channel类型
//实际上是将channel的字节码对象作为参数,创造一个ReflectiveChannelFactory对象
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
//ReflectiveChannelFactory的构造函数
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
至此,channel对象就被创建,之后回到initAndRegister方法,进入下一步,调用init方法。
@Override
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
ServerBootstrap重写了AbstractBootstrap的init方法,所以,这里实际上调用的是ServerBootstrap类的init方法。
在init方法中,首先为一些选项赋值,比如在setChannelOptions中,
static void setChannelOptions(
Channel channel, Map.Entry<ChannelOption<?>, Object>[] options, InternalLogger logger) {
for (Map.Entry<ChannelOption<?>, Object> e: options) {
setChannelOption(channel, e.getKey(), e.getValue(), logger);
}
}
首先将option转化成list,再通过for循环,将每一个选项设置,比如,在server代码中,有一行
.option(ChannelOption.SO_BACKLOG, 128)
就是在这里将SO_BACKLOG=128设置的。
之后,通过channel的pipeline ()方法获得pipeline对象,再向管道中添加处理器,关于这一部分,将在后面分析。
到了这里,完成了对channel对象的初始化,之后开始register。
ChannelFuture regFuture = config().group().register(channel);
这里,config().group()返回的是bossGroup。
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
这里,next()方法是通过chooser来选择下一个线程,实际上,如代码所示,就是自增取余,之后进入register(Channel channel)方法。
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
这里的register实际上调用的是AbstractChannel类的内部类AbstractUnsafe的register方法。
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
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);
}
}
}
在这个方法里面,前面都是一些判断,来到eventLoop.inEventLoop(),这是判断要绑定的线程是否是当前线程,由于现在在初始化服务器,显然不是,进入else语句,让eventLoop自己去执行register0方法。
而通过register0方法,将当前线程注册。到这里,返回了ChannelFuture对象,之后的判断是为了面对异步编程可能出现的问题,这些在上一篇博客中由分析,因此,对initAndRegister的分析先到此为止,至于之前的pipeline的addLast的部分将在本篇博客的第四部分分析。
三、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() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
在doBind0中,依然是创建新的线程,由该线程去完成实际逻辑,channel.bind()方法位于AbstractChannel中,直接调用了pipeline.pipeline()方法。
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
而DefaultChannelPipeline调用了tail.bind()方法,tail实际上是AbstractChannelHandlerContex,可以理解为ChannelHandler的容器,在netty中,ChannelHandler以一个链的形式连接,而head和tail分别是该链的首和尾。
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
ObjectUtil.checkNotNull(localAddress, "localAddress");
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null, false);
}
return promise;
}
从代码可知,这里就是从tail开始反向遍历handler链,直到head,最后会调用AbstractChannel的内部类AbstractUnsafe类的bind方法,而在这个bind方法中,调用了doBind方法,实际上,绑定端口的真正工作其实是在这里完成。
四、pipeline的addLast方法
在DefaultChannelPipeline中,addLast方法实现如代码所示。
@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
ObjectUtil.checkNotNull(handlers, "handlers");
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private static void checkMultiplicity(ChannelHandler handler) {
if (handler instanceof ChannelHandlerAdapter) {
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
h.added = true;
}
}
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
可以看见,addLast方法最后调用的是public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler)方法。首先说明,一般添加的Handler是ChannelInitializer的对象,而根据继承树想上寻找,可以看到,ChannelInitializer确实继承自ChannelHandlerAdapter类,因此,在checkMultiplicity中,handler instanceof ChannelHandlerAdapter 的结果为true。会判断如果有Sharable注解,必须是单例对象,不可重复添加。
之后,创建DefaultChannelHandlerContext对象,与head和tail一致,然后,执行addLast0方法,在addLast0中,可以看到将新建的context的前驱设置为tail的prev,后继设置为tail,再将prev的后继设置为context,tail的前驱设置为context,明白,这就是一个双向链表。
关于pipeline添加handler,就分析这么多了,额外提一句,ChannelInitializer是一个特殊的ChannelHandler,在初始化完成后,会将自己从pipeline中移除。
五、总结
在本篇博客中,分析了ServerBootstrap绑定端口的剩余细节,包括initAndRegister方法,doBind0方法等。此外,还分析了pipeline添加handler的代码,这里提一下,一个channel对应一个pipeline,一个pipeline对应多个ChannelHandlerContext,而每一个ChannelHandlerContext对应一个ChannelHandler,而head和tail则是这个链的首和尾。另外,由于时间原因,就不会分析Bootstrap的connect方法,其逻辑大体上与ServerBootstrap的bind相似。