Netty源码简析之初始化服务端Channel及Selector的注册过程

这里接着上文的《服务端Channel的创建》- https://blog.csdn.net/qq_28666081/article/details/102424327
 
初始化channel很简单,直接看如下代码:
// AbstractBootStrap.java
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        channel = channelFactory.newChannel();
        init(channel);   // 初始化服务端channel,本文重点
        ..............
        ChannelFuture regFuture = config().group().register(channel);   // selector的注册过程,本文重点
 
1 初始化服务端Channel
void init(Channel channel) throws Exception {
    // 第一步:初始化用户传入的自定义参数
    final Map, Object> options = options0();
    synchronized (options) {
        channel.config().setOptions(options);
    }
 
    final Map, Object> attrs = attrs0();
    synchronized (attrs) {
        for (Entry, Object> e: attrs.entrySet()) {
            @SuppressWarnings("unchecked")
            AttributeKey key = (AttributeKey) e.getKey();
            channel.attr(key).set(e.getValue());
        }
    }
 
    ChannelPipeline p = channel.pipeline();
 
    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry, Object>[] currentChildOptions;
    final Entry, Object>[] currentChildAttrs;
    synchronized (childOptions) {
        currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
    }
    synchronized (childAttrs) {
        currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
    }
            // 第二步 创建连接记录器
    p.addLast(new ChannelInitializer() {
        @Override
        public void initChannel(Channel ch) throws Exception {
            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(currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                }
            });
        }
    });
}
 
总结:保存用户自定义的属性,并用这些属性创建一个连接记录器,连接记录器每次收到新连接,都会使用这些属性对新的连接做一些配置
 
2 Selector的注册过程
跟踪最上面代码ChannelFuture regFuture = config().group().register(channel),然后最后可跟踪到如下:
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    .....................
    AbstractChannel.this.eventLoop = eventLoop;  // 分析A点
 
    if (eventLoop.inEventLoop()) {
        register0(promise);    // 分析B点
    } else {
        try {
            eventLoop.execute(new Runnable() {
            @Override
            public void run() {
                register0(promise);
            }
        });
    } catch (Throwable t) {
    .........................
}
从上面代码先看A点,A点是把eventLoop时间暂存起来,供后续使用
 
B点:这里进行了selector的真正注册过程,点进去看大致代码如下:
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();  // 这里最终调用了jdk底层的NIO进行注册
        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);
    }
}
 
 
 
 

few

 

你可能感兴趣的:(netty,channel,JAVA)