0. remeber i’ll be with u,u’ll be with me ~
书接上回
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
channel = channelFactory.newChannel();
// step into ...
// 本章专注于 channel实例 的初始化
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);
}
// 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);
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;
}
1. 进入正题…
@Override
void init(Channel channel) {
// 将之前ServerBootstrap构建过程的ChannelOption参数赋值到netty.channel
setChannelOptions(channel, newOptionsArray(), logger);
// 这里也是赋值一些参数到netty.channel,于我们关心的流程主干影响不大
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
// 获取到前面初始化的Pipeline实例
ChannelPipeline p = channel.pipeline();
// private volatile EventLoopGroup childGroup;
// ServerBootstrap构建过程不是传了俩Group嘛,这里的就是workerGroup,通过命名也能猜到
final EventLoopGroup currentChildGroup = childGroup;
// 同理,这个是构建过程中 childHandler() 的入参
final ChannelHandler currentChildHandler = childHandler;
// 这坨赋值无伤大雅,掠过不解释 ...
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
}
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
// pipeline 做个动作:插入了一个 ChannelInitializer 的 ChannelInboundHandler
// 双向链表的插入逻辑很简单,不细说了,就是直接"挤入"到环上
// 仅仅插入,这里的initChannel()实现方法直到后面才回调到,我们可以先窥一窥
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
// 执行这里的时候,会把我们自定义的handler插入到链表环上
pipeline.addLast(handler);
}
// 下面的插入与我们无瓜 ...
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
netty.channel初始化的东西不多
- 过程中也一并完成了内部pipeline的初始化
- 留了一个坑:pipeline 只插入了 ChannelInitializer 这一个handler, 我们自定义的handler得等到回调时才会插入到pipeline的链表环