上一条博客分析了服务端channel的创建,接着讲一下服务端channel的初始化。
还是从用户代码的bind()方法开始跟,通过doBind()的initAndRegister()方法,里头有个init(channle),
对应服务端就是ServerBootstrap的init()方法,我们看一下这个方法源码
void init(Channel channel) throws Exception {
// 拿到用户代码设置的options
final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
// 把用户设置的options配置到channel上
setChannelOptions(channel, options, logger);
}
// 拿到用户代码设置的attr属性
final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
// 然后把attr属性和值设置到channel上
channel.attr(key).set(e.getValue());
}
}
// 拿到channel创建时创建的pipeline
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
synchronized (childOptions) {
// 保存用户自的childOptions
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
}
synchronized (childAttrs) {
// 保存用户自的childAttrs
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
}
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
// 这里的handler是用户自定义的handler
ChannelHandler handler = config.handler();
if (handler != null) {
// 将用户自定义的handler添加到pipeline
pipeline.addLast(handler);
}
// We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
// In this case the initChannel(...) method will only be called after this method returns. Because
// of this we need to ensure we add our handler in a delayed fashion so all the users handler are
// placed in front of the ServerBootstrapAcceptor.
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 创建一个连接器
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
由上面的源码解析可知,服务端channel初始化比较简单,保存用户代码里设置的options,attrs,handler、childHandler等属性,然后通过这些属性创建一个连接接入器,这个连接器每次接收一个新连接都会使用这些属性。