netty源码阅读之服务器启动之服务端channel的初始化

服务端channel的初始化大致分为以下几个步骤:

1、设置channelOptions,channelAttrs

2、设置childOptions,childAttrs

3、配置服务端pipeline:config handler

4、添加连接器,add serverBootstrapAcceptor,以后新的请求的都通过这个连接器处理。

首先,我们在上一篇文章的AbstractBootstrap的initAndRegister方法里面找到init(channel)这个函数,从这里开始,

现在分析的是服务端的,所以实现是ServerBootstrap的实现:

    @Override
    void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            channel.config().setOptions(options);
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }

        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(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    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(
                                currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

设置channelOptions,channelAttrs

这里的实现很简单,就是把传进来的数据options 和attrs放到map里面:

final Map<ChannelOption<?>, Object> options = options0();
synchronized (options) {
    channel.config().setOptions(options);
}

final Map<AttributeKey<?>, Object> attrs = attrs0();
synchronized (attrs) {
    for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
        @SuppressWarnings("unchecked")
        AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
        channel.attr(key).set(e.getValue());
    }
}

这这里需要说明的是,我们的用户代码没有设置options。

 

设置childOptions,childAttrs

childOptions和childAttrs是新的链接进来之后,我们需要给她设置的属性,而上面一个设置是服务端自己的属性。

用户的代码在这里设置:

           .childOption(ChannelOption.TCP_NODELAY, true)
           .childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")

点进去看其中一个的实现:

    public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
        if (childKey == null) {
            throw new NullPointerException("childKey");
        }
        if (value == null) {
            childAttrs.remove(childKey);
        } else {
            childAttrs.put(childKey, value);
        }
        return this;
    }

而这个childAttrs又是一个hashMap:

    private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();

在ServerBootstrap里面,我们这一步也是简单的复制了一下这两个hashMap:

        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }

简单。

配置服务端pipeline:config handler

后面有一段代码:

ChannelHandler handler = config.handler();

就是配置服务端pipeline。

添加连接器,add ServerBootstrapAcceptor

这一步是最重要的,以后我们新的请求都会经过它来初始化,就是这一句:

 pipeline.addLast(new ServerBootstrapAcceptor(
                                currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));

我们一个个分析参数:

currentChildGroup:

这是从childGroup来的,然后我们用户端代码有一段:b.group(bossGroup, workerGroup),点进去看,这个workerGroup就是我们ServerBootstrap的childGroup:

    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (childGroup == null) {
            throw new NullPointerException("childGroup");
        }
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }

currentChildHandler:

这个其实也是从下面的用户代码进来的:

.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new AuthHandler());
                            //..

                        }
                    });
currentChildOptions, currentChildAttrs:

这个就是我们上面第二步添加的childOptions和childAttrs

初始化比较简单,重点在最后一步添加连接器ServerBootstrapAcceptor。

猜你喜欢

转载自blog.csdn.net/fst438060684/article/details/81428985